From cbddd807d426b272c86f949f520d0d902d0790f7 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 23 Oct 2025 15:39:38 +0300 Subject: [PATCH 01/19] internal audit design complete --- lib/controllers/api_routes/urls.dart | 4 +- .../providers/api/all_requests_provider.dart | 10 + .../providers/api/user_provider.dart | 1 + .../widgets/request_category_list.dart | 4 + lib/main.dart | 12 + lib/models/enums/user_types.dart | 3 +- lib/models/user.dart | 5 + .../service_request_detail_view.dart | 78 ++--- .../create_system_internal_audit_form.dart | 196 +++++++++++ .../pages/internal_audit_detail_page.dart | 178 ++++++++++ .../pages/internal_audit_item_view.dart | 113 ++++++ .../pages/update_internal_audit_page.dart | 327 ++++++++++++++++++ .../internal_audit_finding_type_provider.dart | 34 ++ .../create_request-type_bottomsheet.dart | 11 +- .../my_request/all_requests_filter_page.dart | 4 + .../my_request/my_requests_page.dart | 18 + .../requests/request_paginated_listview.dart | 12 +- .../widgets/request_item_view_list.dart | 8 +- pubspec.lock | 8 + 19 files changed, 975 insertions(+), 51 deletions(-) create mode 100644 lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart create mode 100644 lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart create mode 100644 lib/modules/internal_audit_module/pages/internal_audit_item_view.dart create mode 100644 lib/modules/internal_audit_module/pages/update_internal_audit_page.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 89b58897..49ce0e4d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,8 +4,8 @@ class URLs { static const String appReleaseBuildNumber = "26"; // static const host1 = "https://atomsm.hmg.com"; // production url - // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static String _baseUrl = "$_host/mobile"; static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 470f803d..71d1f46f 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -133,15 +133,25 @@ class AllRequestsProvider extends ChangeNotifier { List getStatues(BuildContext context) { List list = [1, 2, 3, 4]; + //TODO need to refactor this code .... if (context.userProvider.isAssessor) { list = [9]; return list; } + if (context.userProvider.isQualityUser) { + //TODO Need to replace with actual number.. + // list = [10]; + list = [1]; + return list; + } if (!context.userProvider.isNurse) { list.add(5); } + if (context.userProvider.isEngineer) { + list.add(10); + } list.add(6); // task module if (context.settingProvider.isUserFlowMedical && !context.userProvider.isNurse) { diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index f8c93d63..5d1495d5 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -45,6 +45,7 @@ class UserProvider extends ChangeNotifier { bool get isNurse => user!.type == UsersTypes.normal_user; bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl; + bool get isQualityUser => user!.type == UsersTypes.qualityUser; VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); SwipeTransaction _swipeTransactionModel = SwipeTransaction(); diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index f2df78fb..c92ab6b2 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -51,6 +52,9 @@ class RequestCategoryList extends StatelessWidget { return TaskRequestItemView(requestData: request); case 9: return TrafRequestItemView(requestData: request); + //TODO need to verify this ... + case 10: + return InternalAuditItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index 70880a3b..2ee8fd64 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,6 +29,10 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; @@ -98,6 +102,8 @@ import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; +import 'modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'new_views/pages/gas_refill_request_form.dart'; import 'providers/lookups/classification_lookup_provider.dart'; import 'providers/lookups/department_lookup_provider.dart'; @@ -285,6 +291,9 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PpmServiceProvider()), ChangeNotifierProvider(create: (_) => CommentsProvider()), ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()), ///todo deleted //ChangeNotifierProvider(create: (_) => RequestStatusProvider()), @@ -352,6 +361,9 @@ class MyApp extends StatelessWidget { ProfilePage.id: (_) => const ProfilePage(), ReportBugPage.id: (_) => const ReportBugPage(), HelpCenterPage.id: (_) => const HelpCenterPage(), + CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), + CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), + UpdateInternalAuditPage.id: (_) => const UpdateInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart index 63f1d9d7..cd6b5f13 100644 --- a/lib/models/enums/user_types.dart +++ b/lib/models/enums/user_types.dart @@ -3,5 +3,6 @@ enum UsersTypes { normal_user, // 1 nurse, // 1 assessor, - assessorTl + assessorTl, + qualityUser } diff --git a/lib/models/user.dart b/lib/models/user.dart index 3ffc5b29..2c4f3e19 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -97,6 +98,8 @@ class User { UsersTypes? get type { switch (userRoles?.first.value) { + case "R-7": // Head Nurse Role + return UsersTypes.qualityUser; case "R-6": return UsersTypes.engineer; case "R-7": // Nurse Role @@ -107,6 +110,8 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; + //TODO need to replace with actual data when confirm + default: return null; } diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index cb63de73..8b8da1cd 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -72,52 +72,44 @@ class _ServiceRequestDetailViewState extends State { ? const CircularProgressIndicator(color: AppColor.primary10).center : requestProvider.currentWorkOrder == null ? const NoDataFound() - : Stack( - children: [ - Column( + : Column( + children: [ + SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SingleChildScrollView( - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), - initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), - 12.height, - if (context.userProvider.user!.type == UsersTypes.engineer && - !requestProvider.isReadOnlyRequest && - requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ - costCard(context, requestProvider), - 12.height, - ], - contactInfoCard(context, requestProvider.currentWorkOrder!.data!), - 20.height, - ], - ), - ).expanded, - SafeArea( - top: false, - right: false, - left: false, - child: FooterActionButton.requestDetailsFooterWidget( - workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, - status: requestProvider.currentWorkOrder?.data?.status, - isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, - activities: requestProvider.currentWorkOrder!.data?.activities ?? [], - userProvider: _userProvider, - context: context), - ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider), + initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider), + 12.height, + assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider), + 12.height, + if (context.userProvider.user!.type == UsersTypes.engineer && + !requestProvider.isReadOnlyRequest && + requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[ + costCard(context, requestProvider), + 12.height, + ], + contactInfoCard(context, requestProvider.currentWorkOrder!.data!), + 20.height, ], ), - //no need to show timer as discussed with backend - // if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[ - // const TimerWidget(), - // ] - ], - ); + ).expanded, + SafeArea( + top: false, + right: false, + left: false, + child: FooterActionButton.requestDetailsFooterWidget( + workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!, + status: requestProvider.currentWorkOrder?.data?.status, + isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null, + activities: requestProvider.currentWorkOrder!.data?.activities ?? [], + userProvider: _userProvider, + context: context), + ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0), + ], + ); }); } diff --git a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart new file mode 100644 index 00000000..051e2dfd --- /dev/null +++ b/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart @@ -0,0 +1,196 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + +class CreateSystemInternalAuditForm extends StatefulWidget { + static const String id = "/create-system-audit-view"; + + const CreateSystemInternalAuditForm({Key? key}) : super(key: key); + + @override + _CreateSystemInternalAuditFormState createState() => _CreateSystemInternalAuditFormState(); +} +//TODO remove unnecessary code + +class _CreateSystemInternalAuditFormState extends State with TickerProviderStateMixin { + late TextEditingController _commentController; + late InternalAuditProvider _internalAuditProvider; + final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + final List _deviceImages = []; + bool showLoading = false; + + @override + void initState() { + super.initState(); + _commentController = TextEditingController(); + _internalAuditProvider = Provider.of(context, listen: false); + } + + @override + void dispose() { + _commentController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: 'System Internal Audit Checklist'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoCompletePartsField( + assetId: 0, + clearAfterPick: false, + byName: true, + initialValue: _internalAuditModel.woOrderNo ?? "", + onPick: (part) { + _internalAuditModel.woOrderNo = part.name; + setState(() {}); + }, + ), + 12.height, + // if(_internalAuditModel.woOrderNo!=null) + _workOrderInfoWidget(context), + 12.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Finding Type'.addTranslation, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: _internalAuditModel.auditCheckList, + onSelect: (status) { + if (status != null) { + _internalAuditModel.auditCheckList = status; + setState(() {}); + } + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Finding Description'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) {}, + ), + 16.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _deviceImages, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), + ), + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: context.translation.submitRequest, + onPressed: _submit, + ), + ), + ], + ), + ), + ); + } + + Future _submit() async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + List attachement = []; + for (var item in _deviceImages) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + } + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + } + } + + Widget _workOrderInfoWidget(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: showLoading ? Colors.white : const Color(0xffF4F6FC), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xff212936).withOpacity(.03), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Text( + "WO Type", + style: TextStyle( + fontSize: 14.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + color: Colors.black87, + decoration: TextDecoration.none, + ), + ).toShimmer(isShow: showLoading, context: context).expanded, + const Icon( + Icons.info, + color: Color(0xff7D859A), + size: 20, + ), + ], + ), + 6.height, + "${context.translation.site}: ${'ABC'}".bodyText(context), + "${'Eng. Name'.addTranslation}: ${'ABC'}".bodyText(context), + "${'Asset Name'.addTranslation}: ${'ABC'}".bodyText(context), + "${context.translation.model}: ${'ABC'}".bodyText(context), + "${context.translation.manufacture}: ${'ABC'}".bodyText(context), + "${'SN'.addTranslation}: ${'ABC'}".bodyText(context), + "${context.translation.assetNo}: ${'ABC'}".bodyText(context), + ], + ), + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart new file mode 100644 index 00000000..dd36f431 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart @@ -0,0 +1,178 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + +class InternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-internal-audit"; + + final int auditId; + + InternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + + @override + _InternalAuditDetailPageState createState() { + return _InternalAuditDetailPageState(); + } +} + +class _InternalAuditDetailPageState extends State { + bool isWoType = true; + + @override + void initState() { + super.initState(); + //TODO need to get and assign data . + // Provider.of(context, listen: false).getInternalAuditById(widget.auditId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + //TODO need to check when implementing provider needed or not . + return Scaffold( + appBar: const DefaultAppBar(title: "Request Details"), + body: Selector( + selector: (_, provider) => provider.isLoading, + builder: (_, isLoading, __) { + if (isLoading) return const ALoading(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + assetInformation(), + 8.height, + isWoType ? workOrderInformation() : requestDetails(), + 8.height, + //TODO need to check for comments + // if (model.comment?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + Text( + "Comments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // model.comment!.bodyText(context), + // 8.height, + // ], + //TODO need to check for attachments + // if ( _model.attachment.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + // FilesList(images: _model.attachment?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + // ], + ], + ).paddingAll(0).toShadowContainer(context), + ).expanded, + if (context.userProvider.isEngineer) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: "Update", + onPressed: () { + Navigator.pushNamed(context, UpdateInternalAuditPage.id); + }), + ), + ], + ); + }, + )); + } + + Widget workOrderInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "WO Info", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.woNumber}: ${'-'}'.bodyText(context), + '${'WO Type'.addTranslation}: ${'-'}'.bodyText(context), + '${context.translation.site}: ${'-'}'.bodyText(context), + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget requestDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "Request Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + checklistWidget(value: 'Asset Tag'.addTranslation), + checklistWidget(value: 'Expired PM Tag'.addTranslation), + ], + ); + } + + Widget assetInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Asset Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.assetNo}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget checklistWidget({required String value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: true, + activeColor: AppColor.neutral120, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + onChanged: (value) {}, + ), + value.bodyText(context), + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart new file mode 100644 index 00000000..20a81aaf --- /dev/null +++ b/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_detail_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class InternalAuditItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const InternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO need to refactor this code repetation @waseem + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + // (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + ("Internal Audit Request").heading5(context), + // infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context), + + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + // (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), + ("Internal Audit Request").heading5(context), + 8.height, + // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart new file mode 100644 index 00000000..a5b23624 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/update_internal_audit_page.dart @@ -0,0 +1,327 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; +import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; + +class UpdateInternalAuditPage extends StatefulWidget { + static const String id = "update-internal-audit"; + final model; + + const UpdateInternalAuditPage({this.model, Key? key}) : super(key: key); + + @override + State createState() => _UpdateInternalAuditPageState(); +} + +class _UpdateInternalAuditPageState extends State { + final bool _isLoading = false; + double totalWorkingHours = 0.0; + late UserProvider _userProvider; + + // GasRefillDetails _currentDetails = GasRefillDetails(); + final TextEditingController _commentController = TextEditingController(); + final TextEditingController _workingHoursController = TextEditingController(); + + // final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + bool _firstTime = true; + List _attachments = []; + List timerList = []; + + @override + void initState() { + super.initState(); + // if (widget.gasRefillModel != null) { + // _formModel.fromGasRefillModel(widget.gasRefillModel!); + // _commentController.text = _formModel.techComment ?? ""; + // calculateWorkingTime(); + // try { + // _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty); + // _currentDetails.deliverdQty = _deliveredQuantity!.value; + // } catch (ex) {} + // } + // if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) { + // _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList()); + // } + } + + void calculateWorkingTime() { + // final timers = _formModel.gasRefillTimers ?? []; + // totalWorkingHours = timers.fold(0.0, (sum, item) { + // if (item.startDate == null || item.endDate == null) return sum; + // try { + // final start = DateTime.parse(item.startDate!); + // final end = DateTime.parse(item.endDate!); + // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + // return sum + diffInHours; + // } catch (_) { + // return sum; + // } + // }); + // + // timerList = timers.map((e) { + // return TimerHistoryModel( + // id: e.id, + // startTime: e.startDate, + // endTime: e.endDate, + // workingHours: e.workingHours, + // ); + // }).toList(); + } + + @override + void setState(VoidCallback fn) { + if (mounted) super.setState(() {}); + } + + _onSubmit(BuildContext context, int status) async { + bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + + // if (isTimerPickerEnable) { + // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.gasRefillTimePicker == null) { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // } else { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // + // if (_currentDetails.deliverdQty == null) { + // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); + // return false; + // } + // _formModel.gasRefillDetails = []; + // _formModel.gasRefillDetails?.add(_currentDetails); + // + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; + // if (_formModel.gasRefillTimePicker != null) { + // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null + // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // } + // _formModel.timerModelList?.forEach((timer) { + // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: timer.startAt!.toIso8601String(), // Handle potential null + // endDate: timer.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // }); + // _formModel.gasRefillAttachments = []; + // for (var item in _attachments) { + // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; + // _formModel.gasRefillAttachments?.add(GasRefillAttachments( + // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); + // } + + // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { + // Navigator.pop(context); + // if (success) { + // if (status == 1) { + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // // when click complete then this request remove from the list and status changes to closed.. + // _gasRefillProvider?.reset(); + // allRequestsProvider.getAllRequests(context, typeTransaction: 2); + // } + // Navigator.pop(context); + // } + // }); + } + + @override + void dispose() { + _commentController.dispose(); + _workingHoursController.dispose(); + super.dispose(); + } + + void updateTimer({TimerModel? timer}) { + // _formModel.timer = timer; + // if (timer?.startAt != null && timer?.endAt != null) { + // _formModel.timerModelList = _formModel.timerModelList ?? []; + // _formModel.timerModelList!.add(timer!); + // } + // notifyListeners(); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + if (_firstTime) { + String? clientName; + // if (widget.gasRefillModel != null) { + // _gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? ""); + // _formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? "")); + // } else { + // _formModel.timer = null; + // } + } + + return Scaffold( + appBar: DefaultAppBar( + title: 'Update Information'.addTranslation, + onWillPopScope: () { + _onSubmit(context, 0); + }, + ), + key: _scaffoldKey, + body: Form( + key: _formKey, + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + AppTextFormField( + labelText: 'Debrief'.addTranslation, + textInputType: TextInputType.multiline, + hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + alignLabelWithHint: true, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + controller: _commentController, + onChange: (value) {}, + onSaved: (value) {}, + ), + 8.height, + _timerWidget(context, totalWorkingHours), + 16.height, + AttachmentPicker( + label: context.translation.attachFiles, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset( + color: AppColor.primary10, + ), + ), + 8.height, + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: () => _onSubmit(context, 0), + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () => _onSubmit(context, 1), + ).expanded, + ], + ), + ), + ], + )), + ), + ).handlePopScope( + cxt: context, + onSave: () { + _onSubmit(context, 0); + }); + } + + Widget _timerWidget(BuildContext context, double totalWorkingHours) { + TimerModel? timer = TimerModel(); + TimerModel? timerPicker; + List? timerModelList = []; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppTimer( + label: context.translation.workingHours, + timer: timer, + // pickerFromDate: DateTime.tryParse(widget.gasRefillModel?.createdDate ?? ''), + pickerFromDate: DateTime.tryParse(''), + pickerTimer: timerPicker, + onPick: (time) { + //timerPicker = time; + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + // color: AppColor.neutral100, + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + return true; + }, + ), + if (totalWorkingHours > 0.0) ...[ + 12.height, + WorkingTimeTile( + timerList: timerList, + totalWorkingTime: totalWorkingHours, + ), + ], + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart new file mode 100644 index 00000000..c9ee41a8 --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditFindingTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index cca09e6e..1988336f 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; @@ -7,6 +9,8 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -90,8 +94,11 @@ class CreateRequestModel { static List requestsList(BuildContext context) { List list = []; - - if (context.userProvider.isAssessor) { + log('user type is ${context.userProvider.isQualityUser}'); + if (context.userProvider.isQualityUser) { + list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id)); + list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id)); + } else if (context.userProvider.isAssessor) { list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); } else if (context.userProvider.isEngineer) { if (Provider.of(context, listen: false).engineerCanCreateCM) { diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart index c1c4729f..e6521f23 100644 --- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart +++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart @@ -70,6 +70,7 @@ class _AllRequestsFilterPageState extends State { if (isEngineer) { types[context.translation.recurrentWo] = 5; + types["Internal Audit".addTranslation] = 10; } if (context.settingProvider.isUserFlowMedical) { @@ -79,8 +80,11 @@ class _AllRequestsFilterPageState extends State { if (!isEngineer) { types['TRAF'] = 9; } + if (context.userProvider.isAssessor) { types = {"TRAF": 9}; + }if (context.userProvider.isQualityUser) { + types = {"Internal Audit": 10}; } final statuses = { diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 8ac38ab6..30f86273 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -1,5 +1,7 @@ //request main page +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; @@ -40,9 +42,11 @@ class _MyRequestsPageState extends State { Request(2, context.translation.gasRefill), Request(3, context.translation.transferAsset), Request(4, context.translation.preventiveMaintenance), + ]; if (Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) { requestsList.add(Request(5, context.translation.recurrentWo)); + } //TODO unCommit this to enable task requestsList.add(Request(6, context.translation.taskRequest)); @@ -53,6 +57,11 @@ class _MyRequestsPageState extends State { if (context.userProvider.user!.type == UsersTypes.normal_user) { requestsList.add(Request(9, 'TRAF')); } + if (context.userProvider.isEngineer) { + //TODO need to replace with actual number. + // requestsList.add(Request(10, 'Internal Audit')); + requestsList.add(Request(1, 'Internal Audit')); + } if (context.userProvider.isAssessor) { requestsList = [ @@ -60,6 +69,15 @@ class _MyRequestsPageState extends State { Request(9, 'TRAF'), ]; } + if (context.userProvider.isQualityUser) { + requestsList = [ + Request(null, context.translation.allWorkOrder), + //TODO need to replace with actual number. + + // Request(10, 'Internal Audit'), + Request(1, 'Internal Audit'), + ]; + } _provider = Provider.of(context, listen: false); _provider!.reset(); diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index d3064427..7b172e50 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -46,6 +47,7 @@ class RequestPaginatedListview extends StatelessWidget { } Widget _buildRequestItem(Data request) { + //TODO need to replace with switch statement bool isServiceRequest = request.transactionNo == 1; bool isGasRefill = request.transactionNo == 2; bool isAssetTransfer = request.transactionNo == 3; @@ -53,6 +55,7 @@ class RequestPaginatedListview extends StatelessWidget { bool isRecurrentTask = request.transactionNo == 5; bool isTask = request.transactionNo == 6; bool isTRAF = request.transactionNo == 9; + bool isInternalAudit = request.transactionNo == 10; if (isServiceRequest) { return ServiceRequestItemView(requestData: request, refreshData: false); @@ -66,9 +69,14 @@ class RequestPaginatedListview extends StatelessWidget { return RecurrentWoItemView(requestData: request); } else if (isTask) { return TaskRequestItemView(requestData: request); - } else if (isTRAF) { + } + else if (isTRAF) { return TrafRequestItemView(requestData: request); - } else { + } + else if (isInternalAudit) { + return InternalAuditItemView(requestData: request); + } + else { return Container( height: 100, width: double.infinity, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index e29703d4..08b1f51a 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -4,6 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; @@ -29,8 +30,10 @@ class RequestItemViewList extends StatelessWidget { itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); switch (list[index].transactionType) { + // case 1: + // return ServiceRequestItemView(requestDetails: list[index]); case 1: - return ServiceRequestItemView(requestDetails: list[index]); + return InternalAuditItemView(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -45,6 +48,9 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 9: return TrafRequestItemView(requestDetails: list[index]); + //Need to verify the type No.. + case 10: + return InternalAuditItemView(requestDetails: list[index]); default: Container( height: 100, diff --git a/pubspec.lock b/pubspec.lock index 701decdc..fdc4903d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -177,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + clipboard: + dependency: "direct main" + description: + name: clipboard + sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102" + url: "https://pub.dev" + source: hosted + version: "2.0.2" clock: dependency: transitive description: From 09843a9625ac0bfbcf073bca35a10a278b56f5a0 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Tue, 28 Oct 2025 10:20:07 +0300 Subject: [PATCH 02/19] Ui Changes --- .../models/internal_audit_model.dart | 29 ++++ .../create_equipment_internal_audit_form.dart | 138 ++++++++++++++++++ .../internal_audit_checklist_provider.dart | 36 +++++ .../provider/internal_audit_provider.dart | 42 ++++++ 4 files changed, 245 insertions(+) create mode 100644 lib/modules/internal_audit_module/models/internal_audit_model.dart create mode 100644 lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_provider.dart diff --git a/lib/modules/internal_audit_module/models/internal_audit_model.dart b/lib/modules/internal_audit_module/models/internal_audit_model.dart new file mode 100644 index 00000000..693b384d --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_model.dart @@ -0,0 +1,29 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/lookup.dart'; + +class InternalAuditModel { + String? id; + int? deviceId; + String? deviceArName; + String? woOrderNo; + List? devicePhotos; + Lookup? auditCheckList; + String? comments; + Asset? device; + + InternalAuditModel({ + this.id, + this.deviceArName, + this.devicePhotos, + this.deviceId, + this.woOrderNo, + this.comments, + }); + +} + diff --git a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart new file mode 100644 index 00000000..83655836 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart @@ -0,0 +1,138 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; + +class CreateEquipmentInternalAuditForm extends StatefulWidget { + static const String id = "/create-internal-audit-view"; + + const CreateEquipmentInternalAuditForm({Key? key}) : super(key: key); + + @override + _CreateEquipmentInternalAuditFormState createState() => _CreateEquipmentInternalAuditFormState(); +} + +class _CreateEquipmentInternalAuditFormState extends State with TickerProviderStateMixin { + late TextEditingController _commentController; + final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final List _deviceImages = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + _commentController = TextEditingController(); + } + + @override + void dispose() { + _commentController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: 'Equipment Internal Audit Checklist'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AssetPicker( + device: _internalAuditModel.device, + borderColor: AppColor.black20, + buttonColor: AppColor.white936, + onPick: (asset) async { + _internalAuditModel.device = asset; + setState(() {}); + }, + ), + 16.height, + SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Internal Audit Checklist'.addTranslation, + showShadow: false, + initialValue: _internalAuditModel.auditCheckList, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + onSelect: (status) { + if (status != null) { + _internalAuditModel.auditCheckList = status; + setState(() {}); + } + }, + ), + 16.height, + AppTextFormField( + backgroundColor: AppColor.fieldBgColor(context), + labelText: 'Remarks'.addTranslation, + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + showShadow: false, + onSaved: (text) {}, + ), + 16.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _deviceImages, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), + ), + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton(label: context.translation.submitRequest, buttonColor: AppColor.primary10, onPressed: _submit), + ), + ], + ), + ), + ); + } + + Future _submit() async { + InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + List attachement = []; + for (var item in _deviceImages) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + } + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + } + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart new file mode 100644 index 00000000..3240bf2d --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart @@ -0,0 +1,36 @@ + +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditCheckListProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart new file mode 100644 index 00000000..983bd6ca --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -0,0 +1,42 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/device/asset_search.dart'; +import 'package:test_sa/models/lookup.dart'; + +class InternalAuditProvider extends ChangeNotifier { + final pageItemNumber = 10; + final searchPageItemNumber = 10; + int pageNo = 1; + void reset() { + pageNo = 1; + stateCode = null; + } + int? stateCode; + bool isDetailLoading = false; + bool nextPage = false; + bool isNextPageLoading = false; + bool isLoading = false; + Future getInternalAuditById(int id) async { + try { + isLoading = true; + notifyListeners(); + //Need to replace + Response response = await ApiManager.instance.get("${URLs.getTRAFById}?id=$id"); + if (response.statusCode >= 200 && response.statusCode < 300) { + // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); + } + isLoading = false; + notifyListeners(); + return 0; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } +} From a8e8774040aa97fc7a5d89ebae29d6826f50d88d Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 6 Nov 2025 11:42:46 +0300 Subject: [PATCH 03/19] internal audit api's implementation in progress --- lib/controllers/api_routes/urls.dart | 11 + .../providers/api/all_requests_provider.dart | 5 +- .../widgets/request_category_list.dart | 6 +- lib/main.dart | 6 +- .../equipment_internal_audit_data_model.dart | 284 ++++++++++++++++++ .../equipment_internal_audit_form_model.dart | 41 +++ .../internal_audit_attachment_model.dart | 23 ++ .../models/internal_audit_model.dart | 29 -- .../system_internal_audit_form_model.dart | 82 +++++ .../create_equipment_internal_audit_form.dart | 59 ++-- .../equipment_internal_audit_detail_page.dart | 192 ++++++++++++ .../equipment_internal_audit_item_view.dart} | 25 +- .../create_system_internal_audit_form.dart | 107 +++++-- ..._audit_work_order_auto_complete_field.dart | 149 +++++++++ .../system_internal_audit_detail_page.dart} | 13 +- .../system_internal_audit_item_view.dart | 118 ++++++++ .../internal_audit_checklist_provider.dart | 2 +- .../internal_audit_finding_type_provider.dart | 2 +- .../provider/internal_audit_provider.dart | 80 ++++- .../internal_audit_wo_type_provider.dart | 35 +++ .../create_request-type_bottomsheet.dart | 4 +- .../my_request/my_requests_page.dart | 11 +- .../requests/request_paginated_listview.dart | 19 +- .../widgets/request_item_view_list.dart | 28 +- 24 files changed, 1202 insertions(+), 129 deletions(-) create mode 100644 lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart create mode 100644 lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart create mode 100644 lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart delete mode 100644 lib/modules/internal_audit_module/models/internal_audit_model.dart create mode 100644 lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart rename lib/modules/internal_audit_module/pages/{ => equipment_internal_audit}/create_equipment_internal_audit_form.dart (71%) create mode 100644 lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart rename lib/modules/internal_audit_module/pages/{internal_audit_item_view.dart => equipment_internal_audit/equipment_internal_audit_item_view.dart} (77%) rename lib/modules/internal_audit_module/pages/{ => system_internal_audit}/create_system_internal_audit_form.dart (66%) create mode 100644 lib/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart rename lib/modules/internal_audit_module/pages/{internal_audit_detail_page.dart => system_internal_audit/system_internal_audit_detail_page.dart} (94%) create mode 100644 lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart create mode 100644 lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 49ce0e4d..dad15d8d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -300,6 +300,7 @@ class URLs { static get getPentry => "$_baseUrl/return/pentry/details"; // get static get updatePentry => "$_baseUrl/Visit/UpdateVisit"; // get static get getPentryTaskStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=403"; // get + // get static get getPentryVisitStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=402"; // get static get getPentryStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=401"; // get // contacts @@ -310,4 +311,14 @@ class URLs { static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // add + +//internal Audit + static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemById"; + static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; + static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; + static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; + static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 71d1f46f..99f77a02 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -140,9 +140,8 @@ class AllRequestsProvider extends ChangeNotifier { return list; } if (context.userProvider.isQualityUser) { - //TODO Need to replace with actual number.. - // list = [10]; - list = [1]; + + list = [10,11]; return list; } diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index c92ab6b2..639b3e6a 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -54,7 +54,9 @@ class RequestCategoryList extends StatelessWidget { return TrafRequestItemView(requestData: request); //TODO need to verify this ... case 10: - return InternalAuditItemView(requestData: request); + return EquipmentInternalAuditItemView(requestData: request); + case 11: + return EquipmentInternalAuditItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/main.dart b/lib/main.dart index 2ee8fd64..a2f9bdca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,10 +29,11 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; @@ -292,6 +293,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => CommentsProvider()), ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()), ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()), + ChangeNotifierProvider(create: (_) => InternalAuditWoTypeProvider()), ChangeNotifierProvider(create: (_) => InternalAuditProvider()), ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()), diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart new file mode 100644 index 00000000..411789ec --- /dev/null +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -0,0 +1,284 @@ + class EquipmentInternalAuditDataModel { + int? id; + String? requestNo; + String? createdDate; + int? requestNoSequence; + Auditor? auditor; + Status? status; + Asset? asset; + AssignEmployee? assignEmployee; + dynamic manufacture; + String? remarks; + List? equipmentsFindings; + List? attachments; + + EquipmentInternalAuditDataModel({ + this.id, + this.requestNo, + this.createdDate, + this.requestNoSequence, + this.auditor, + this.status, + this.asset, + this.assignEmployee, + this.manufacture, + this.remarks, + this.equipmentsFindings, + this.attachments, + }); + + EquipmentInternalAuditDataModel.fromJson(Map json) { + id = json['id']; + requestNo = json['requestNo']; + createdDate = json['createdDate']; + requestNoSequence = json['requestNoSequence']; + auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null; + status = json['status'] != null ? Status.fromJson(json['status']) : null; + asset = json['asset'] != null ? Asset.fromJson(json['asset']) : null; + assignEmployee = json['assignEmployee'] != null ? AssignEmployee.fromJson(json['assignEmployee']) : null; + manufacture = json['manufacture']; + remarks = json['remarks']; + if (json['equipmentsFindings'] != null) { + equipmentsFindings = []; + json['equipmentsFindings'].forEach((v) { + equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); + }); + } + attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['requestNo'] = requestNo; + data['createdDate'] = createdDate; + data['requestNoSequence'] = requestNoSequence; + if (auditor != null) { + data['auditor'] = auditor!.toJson(); + } + if (status != null) { + data['status'] = status!.toJson(); + } + if (asset != null) { + data['asset'] = asset!.toJson(); + } + if (assignEmployee != null) { + data['assignEmployee'] = assignEmployee!.toJson(); + } + data['manufacture'] = manufacture; + data['remarks'] = remarks; + if (equipmentsFindings != null) { + data['equipmentsFindings'] = + equipmentsFindings!.map((v) => v.toJson()).toList(); + } + data['attachments'] = attachments; + return data; + } +} + +class Auditor { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + Auditor({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + Auditor.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} + +class Status { + int? id; + String? name; + int? value; + + Status({this.id, this.name, this.value}); + + Status.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['value'] = value; + return data; + } +} + +class Asset { + int? id; + String? assetNumber; + String? assetSerialNo; + String? assetName; + String? modelName; + String? manufacturerName; + String? siteName; + int? siteId; + String? modelDefinition; + + Asset({ + this.id, + this.assetNumber, + this.assetSerialNo, + this.assetName, + this.modelName, + this.manufacturerName, + this.siteName, + this.siteId, + this.modelDefinition, + }); + + Asset.fromJson(Map json) { + id = json['id']; + assetNumber = json['assetNumber']; + assetSerialNo = json['assetSerialNo']; + assetName = json['assetName']; + modelName = json['modelName']; + manufacturerName = json['manufacturerName']; + siteName = json['siteName']; + siteId = json['siteId']; + modelDefinition = json['modelDefinition']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetNumber'] = assetNumber; + data['assetSerialNo'] = assetSerialNo; + data['assetName'] = assetName; + data['modelName'] = modelName; + data['manufacturerName'] = manufacturerName; + data['siteName'] = siteName; + data['siteId'] = siteId; + data['modelDefinition'] = modelDefinition; + return data; + } +} + +class AssignEmployee { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + AssignEmployee({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + AssignEmployee.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} + +class EquipmentsFinding { + int? id; + Finding? finding; + + EquipmentsFinding({this.id, this.finding}); + + EquipmentsFinding.fromJson(Map json) { + id = json['id']; + finding = json['finding'] != null ? Finding.fromJson(json['finding']) : null; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + if (finding != null) { + data['finding'] = finding!.toJson(); + } + return data; + } +} + +class Finding { + int? id; + String? name; + int? value; + + Finding({this.id, this.name, this.value}); + + Finding.fromJson(Map json) { + id = json['id']; + name = json['name']; + value = json['value']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['value'] = value; + return data; + } +} diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart new file mode 100644 index 00000000..e6a79e91 --- /dev/null +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart @@ -0,0 +1,41 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class EquipmentInternalAuditFormModel { + int? id=0; + String? deviceArName; + String? auditorId; + String? woOrderNo; + List? devicePhotos; + List findings =[]; + List attachments = []; + String? remarks; + Asset? device; + EquipmentInternalAuditFormModel({ + this.id, + this.deviceArName, + this.auditorId, + this.devicePhotos, + this.woOrderNo, + this.remarks, + }); + + Map toJson() { + return { + 'id': id??0, + 'assetId': device?.id, + 'auditorId': auditorId, + 'findings': findings.map((e) => {'findingId': e.value}).toList(), + 'attachments': attachments.map((e) => e.toJson()).toList(), + 'remarks': remarks, + }; + } + + +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart new file mode 100644 index 00000000..a81f2d17 --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart @@ -0,0 +1,23 @@ +class InternalAuditAttachments { + InternalAuditAttachments({this.id,this.originalName, this.name,this.createdBy}); + + int? id; + String? name; + String? originalName; + String ?createdBy; + InternalAuditAttachments.fromJson(Map json) { + id = json['id']; + name = json['name']; + originalName = json['originalName']; + createdBy = json['createdBy']; + } + + Map toJson() { + final Map data = {}; + // data['id'] = id; + data['name'] = name; + data['originalName'] = originalName; + // data['createdBy'] = createdBy; + return data; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/internal_audit_model.dart b/lib/modules/internal_audit_module/models/internal_audit_model.dart deleted file mode 100644 index 693b384d..00000000 --- a/lib/modules/internal_audit_module/models/internal_audit_model.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/src/widgets/framework.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:test_sa/controllers/api_routes/urls.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/models/device/asset.dart'; -import 'package:test_sa/models/fault_description.dart'; -import 'package:test_sa/models/lookup.dart'; - -class InternalAuditModel { - String? id; - int? deviceId; - String? deviceArName; - String? woOrderNo; - List? devicePhotos; - Lookup? auditCheckList; - String? comments; - Asset? device; - - InternalAuditModel({ - this.id, - this.deviceArName, - this.devicePhotos, - this.deviceId, - this.woOrderNo, - this.comments, - }); - -} - diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart new file mode 100644 index 00000000..9750e9e0 --- /dev/null +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -0,0 +1,82 @@ + +import 'dart:developer'; + +import 'package:test_sa/models/lookup.dart'; + +class SystemInternalAuditFormModel { + int? id = 0; + String? auditorId; + String? assignEmployeeId; + Lookup? findingType; + String? findingDescription; + Lookup? workOrderType; + int? correctiveMaintenanceId; + int? planPreventiveVisitId; + int? assetTransferId; + int? taskJobId; + int? taskAlertJobId; + int? gasRefillId; + int? planRecurrentTaskId; + int? statusId; + + SystemInternalAuditFormModel({ + this.id, + this.auditorId, + this.assignEmployeeId, + this.findingType, + this.findingDescription, + this.workOrderType, + this.correctiveMaintenanceId, + this.planPreventiveVisitId, + this.assetTransferId, + this.taskJobId, + this.taskAlertJobId, + this.gasRefillId, + this.planRecurrentTaskId, + this.statusId, + }); + + Map toJson() { + return { + 'id': id, + 'auditorId': auditorId, + 'assignEmployeeId': assignEmployeeId, + 'findingTypeId': findingType?.id, + 'findingDescription': findingDescription, + 'workOrderTypeId': workOrderType?.id, + 'correctiveMaintenanceId': correctiveMaintenanceId, + 'planPreventiveVisitId': planPreventiveVisitId, + 'assetTransferId': assetTransferId, + 'taskJobId': taskJobId, + 'taskAlertJobId': taskAlertJobId, + 'gasRefillId': gasRefillId, + 'planRecurrentTaskId': planRecurrentTaskId, + 'statusId': statusId, + }; + } +} + +class WoAutoCompleteModel { + int? id; + String? workOrderNo; + String? displayName; + + WoAutoCompleteModel({this.id, this.workOrderNo, this.displayName}); + + WoAutoCompleteModel.fromJson(Map json) { + id = json['id']; + workOrderNo = json['workOrderNo']; + displayName = json['workOrderNo']; + } + + Map toJson() { + final Map data = {}; + data['id'] =id; + data['woOrderNo'] = workOrderNo; + data['displayName'] = workOrderNo; + return data; + } +} + + + diff --git a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart similarity index 71% rename from lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart rename to lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart index 83655836..db29aee6 100644 --- a/lib/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart @@ -9,24 +9,24 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; -import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; -import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart'; import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; -import '../../../../../../new_views/common_widgets/default_app_bar.dart'; class CreateEquipmentInternalAuditForm extends StatefulWidget { - static const String id = "/create-internal-audit-view"; + static const String id = "/create-equipment-internal-audit-form"; const CreateEquipmentInternalAuditForm({Key? key}) : super(key: key); @@ -36,10 +36,11 @@ class CreateEquipmentInternalAuditForm extends StatefulWidget { class _CreateEquipmentInternalAuditFormState extends State with TickerProviderStateMixin { late TextEditingController _commentController; - final InternalAuditModel _internalAuditModel = InternalAuditModel(); - final List _deviceImages = []; + final EquipmentInternalAuditFormModel _equipmentinternalAuditModel = EquipmentInternalAuditFormModel(); + final List _attachments = []; final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); + FocusNode auditCheckListNode = FocusNode(); @override void initState() { @@ -68,28 +69,27 @@ class _CreateEquipmentInternalAuditFormState extends State( + //TODO need to check layout issue... + MultipleItemDropDownMenu( context: context, - height: 56.toScreenHeight, - title: 'Internal Audit Checklist'.addTranslation, - showShadow: false, - initialValue: _internalAuditModel.auditCheckList, - backgroundColor: AppColor.fieldBgColor(context), showAsBottomSheet: true, - onSelect: (status) { - if (status != null) { - _internalAuditModel.auditCheckList = status; - setState(() {}); - } + backgroundColor: AppColor.neutral100, + showShadow: false, + showCancel: true, + requestById: context.userProvider.user?.clientId, + title: 'Internal Audit Checklist'.addTranslation, + initialValue: _equipmentinternalAuditModel.findings, + onSelect: (value) { + _equipmentinternalAuditModel.findings = value ?? []; }, ), 16.height, @@ -100,14 +100,17 @@ class _CreateEquipmentInternalAuditFormState extends State(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - List attachement = []; - for (var item in _deviceImages) { + _equipmentinternalAuditModel.attachments = []; + for (var item in _attachments) { String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + _equipmentinternalAuditModel.attachments.add(InternalAuditAttachments(id: item.id, name: fileName)); } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + _equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID; + bool status = await internalAuditProvider.addEquipmentInternalAudit(context: context, request: _equipmentinternalAuditModel); + Navigator.pop(context); + if(status){ + Navigator.pop(context); + } } } } diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart new file mode 100644 index 00000000..465a42db --- /dev/null +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -0,0 +1,192 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + +class EquipmentInternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-internal-audit"; + + final int auditId; + + const EquipmentInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + + @override + _EquipmentInternalAuditDetailPageState createState() { + return _EquipmentInternalAuditDetailPageState(); + } +} + +class _EquipmentInternalAuditDetailPageState extends State { + bool isWoType = true; + EquipmentInternalAuditDataModel? model; + late InternalAuditProvider _internalAuditProvider; + + @override + void initState() { + super.initState(); + _internalAuditProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getAuditData(); + }); + } + + Future getAuditData() async { + model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + //TODO need to check when implementing provider needed or not . + return Scaffold( + appBar: const DefaultAppBar(title: "Request Details"), + body: Selector( + selector: (_, provider) => provider.isLoading, + builder: (_, isLoading, __) { + if (isLoading) return const ALoading(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + assetDetails(), + 8.height, + requestDetails(), + 8.height, + //TODO need to check for comments + // if (model.comment?.isNotEmpty ?? false) ...[ + const Divider().defaultStyle(context), + Text( + "Comments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + // model.comment!.bodyText(context), + // 8.height, + // ], + //TODO need to check for attachments + // if ( _model.attachment.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + // FilesList(images: _model.attachment?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + // ], + ], + ).paddingAll(0).toShadowContainer(context), + ).expanded, + if (context.userProvider.isEngineer) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: "Update", + onPressed: () { + Navigator.pushNamed(context, UpdateInternalAuditPage.id); + }), + ), + ], + ); + }, + )); + } + + Widget workOrderInformation() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "WO Info", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.woNumber}: ${'-'}'.bodyText(context), + '${'WO Type'.addTranslation}: ${'-'}'.bodyText(context), + '${context.translation.site}: ${'-'}'.bodyText(context), + '${context.translation.assetName}: ${'-'}'.bodyText(context), + '${context.translation.manufacture}: ${'-'}'.bodyText(context), + '${context.translation.model}: ${'-'}'.bodyText(context), + ], + ); + } + + Widget requestDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider().defaultStyle(context), + Text( + "Request Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty) + ...model!.equipmentsFindings!.map((item) { + final findingName = item.finding?.name ?? 'Unknown'; + return checklistWidget(value: findingName.addTranslation); + }).toList() + else + Text('No findings available'.addTranslation), + ], + ); + } + + Widget assetDetails() { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Asset Details", + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 6.height, + '${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.bodyText(context), + '${context.translation.assetNo}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context), + '${context.translation.manufacture}: ${model?.asset?.manufacturerName ?? '-'}'.bodyText(context), + '${context.translation.model}: ${model?.asset?.modelName ?? '-'}'.bodyText(context), + ], + ); + } + + Widget checklistWidget({required String value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + value: true, + activeColor: AppColor.neutral120, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity(horizontal: -4, vertical: -3), + onChanged: (value) {}, + ), + value.bodyText(context), + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart similarity index 77% rename from lib/modules/internal_audit_module/pages/internal_audit_item_view.dart rename to lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart index 20a81aaf..4c4bbb57 100644 --- a/lib/modules/internal_audit_module/pages/internal_audit_item_view.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -6,20 +8,21 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_detail_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; -class InternalAuditItemView extends StatelessWidget { +class EquipmentInternalAuditItemView extends StatelessWidget { final Data? requestData; final RequestsDetails? requestDetails; final bool showShadow; - const InternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + const EquipmentInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); @override Widget build(BuildContext context) { //TODO need to refactor this code repetation @waseem + log('request details ${requestDetails?.toJson()}'); if (requestData != null) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -41,9 +44,8 @@ class InternalAuditItemView extends StatelessWidget { ], ), 8.height, - // (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), - ("Internal Audit Request").heading5(context), - // infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context), + (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context), 8.height, Row( @@ -59,7 +61,7 @@ class InternalAuditItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!))); }); } return Column( @@ -82,10 +84,11 @@ class InternalAuditItemView extends StatelessWidget { ], ), 8.height, - // (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), - ("Internal Audit Request").heading5(context), + (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), 8.height, - // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), + infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), + infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), 8.height, Row( mainAxisSize: MainAxisSize.min, @@ -100,7 +103,7 @@ class InternalAuditItemView extends StatelessWidget { ), ], ).toShadowContainer(context, withShadow: showShadow).onPress(() async { - Navigator.push(context, MaterialPageRoute(builder: (context) => InternalAuditDetailPage(auditId: requestDetails!.id!))); + Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!))); }); } diff --git a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart similarity index 66% rename from lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart rename to lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index 051e2dfd..64e8408b 100644 --- a/lib/modules/internal_audit_module/pages/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -13,10 +14,13 @@ import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_mo import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/internal_audit_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; @@ -25,7 +29,7 @@ import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart'; -import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +import '../../../../../../../new_views/common_widgets/default_app_bar.dart'; class CreateSystemInternalAuditForm extends StatefulWidget { static const String id = "/create-system-audit-view"; @@ -40,22 +44,25 @@ class CreateSystemInternalAuditForm extends StatefulWidget { class _CreateSystemInternalAuditFormState extends State with TickerProviderStateMixin { late TextEditingController _commentController; late InternalAuditProvider _internalAuditProvider; - final InternalAuditModel _internalAuditModel = InternalAuditModel(); + final SystemInternalAuditFormModel _model = SystemInternalAuditFormModel(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); final List _deviceImages = []; + late TextEditingController _woAutoCompleteController; bool showLoading = false; @override void initState() { super.initState(); _commentController = TextEditingController(); + _woAutoCompleteController = TextEditingController(); _internalAuditProvider = Provider.of(context, listen: false); } @override void dispose() { _commentController.dispose(); + _woAutoCompleteController.dispose(); super.dispose(); } @@ -73,13 +80,31 @@ class _CreateSystemInternalAuditFormState extends State( + context: context, + height: 56.toScreenHeight, + title: 'Wo Type'.addTranslation, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: _model.workOrderType, + onSelect: (status) { + if (status != null) { + _model.workOrderType = status; + _clearWorkOrderSelection(); + _woAutoCompleteController.clear(); + setState(() {}); + } + }, + ), + 12.height, + SystemAuditWoAutoCompleteField( + woTypeId: _model.workOrderType?.value, + controller: _woAutoCompleteController, clearAfterPick: false, - byName: true, - initialValue: _internalAuditModel.woOrderNo ?? "", - onPick: (part) { - _internalAuditModel.woOrderNo = part.name; + initialValue: '', + onPick: (wo) { + updateWorkOrderReference(woTypeId: _model.workOrderType?.value, selectedId:wo.id); setState(() {}); }, ), @@ -94,10 +119,10 @@ class _CreateSystemInternalAuditFormState extends State _SystemAuditWoAutoCompleteFieldState(); +} + +class _SystemAuditWoAutoCompleteFieldState extends State { + late InternalAuditProvider _provider; + + // + // late TextEditingController _controller; + + bool loading = false; + + @override + void initState() { + // w controller = widget.controller ?? TextEditingController(text: widget.initialValue); + super.initState(); + _provider = Provider.of(context, listen: false); + } + + @override + void didUpdateWidget(covariant SystemAuditWoAutoCompleteField oldWidget) { + // if (widget.initialValue != oldWidget.initialValue) { + // // _controller = widget.controller ?? TextEditingController(text: widget.initialValue); + // } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + if (widget.controller == null) { + // _controller.dispose(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10)); + return Container( + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) async { + if (textEditingValue.text.isEmpty) { + if (loading) { + setState(() { + loading = false; + }); + } + return const Iterable.empty(); + } + if (!loading) { + setState(() { + loading = true; + }); + } + List workOrders = (await _provider.getWorkOrderByWoType(text: textEditingValue.text, woId:widget.woTypeId)); + setState(() { + loading = false; + }); + return workOrders; + }, + displayStringForOption: (WoAutoCompleteModel option) => option.displayName ?? '', + fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { + return TextField( + controller: widget.controller, + focusNode: fieldFocusNode, + style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), + textAlign: TextAlign.start, + decoration: InputDecoration( + border: border, + disabledBorder: border, + focusedBorder: border, + enabledBorder: border, + errorBorder: border, + contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth), + constraints: const BoxConstraints(), + suffixIconConstraints: const BoxConstraints(maxHeight: 24, maxWidth: 24 + 8), + filled: true, + fillColor: AppColor.fieldBgColor(context), + errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), + floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), + labelText: context.translation.woNumber, + labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), + suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null, + ), + textInputAction: TextInputAction.search, + onChanged: (text) { + fieldTextEditingController.text = text; + }, + onSubmitted: (String value) { + onFieldSubmitted(); + }, + ); + }, + onSelected: (WoAutoCompleteModel selection) { + if (widget.clearAfterPick) { + widget.controller.clear(); + } else { + widget.controller.text = (selection.displayName ?? ""); + } + widget.onPick(selection); + }, + ), + ); + } + + // String getUrl(int? woTypeId) { + // if (woTypeId == null) return ''; + // String base = URLs.woAutoCompleteBase; + // var urlMap = { + // 1: '$base/ServiceRequest/WorkOrderAutoComplete', // CM + // 2: '$base/GasRefill/GetGasRefillAutoComplete', // Gas Refill + // 3: '$base/AssetTransfer/GetAssetTransferAutoComplete', // Asset Transfer + // 4: '$base/PlanPreventiveVisit/GetAutoCompletePlanPreventiveVisit', // PPM Request + // 5: '$base/PlanRecurrentTasks/GetPlanRecurrentTask', // Recurrent WO + // 6: '$base/TaskJobs/AutocompleteTaskJob', // Task + // 7: '$base/TaskJobs/AutocompleteTaskJob', // Recall & Alert + // }; + // return urlMap[woTypeId] ?? ''; + // } +} diff --git a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart similarity index 94% rename from lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart rename to lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart index dd36f431..a4f459fe 100644 --- a/lib/modules/internal_audit_module/pages/internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart @@ -16,20 +16,19 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; -class InternalAuditDetailPage extends StatefulWidget { - static const String id = "/details-internal-audit"; - +class SystemInternalAuditDetailPage extends StatefulWidget { + static const String id = "/details-system-internal-audit"; final int auditId; - InternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); + SystemInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key); @override - _InternalAuditDetailPageState createState() { - return _InternalAuditDetailPageState(); + _SystemInternalAuditDetailPageState createState() { + return _SystemInternalAuditDetailPageState(); } } -class _InternalAuditDetailPageState extends State { +class _SystemInternalAuditDetailPageState extends State { bool isWoType = true; @override diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart new file mode 100644 index 00000000..db6e2c11 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart @@ -0,0 +1,118 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/all_requests_and_count_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/widgets/requests/request_status.dart'; + +class SystemInternalAuditItemView extends StatelessWidget { + final Data? requestData; + final RequestsDetails? requestDetails; + final bool showShadow; + + const SystemInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO need to refactor this code repetation @waseem + log('request details ${requestDetails?.toJson()}'); + if (requestData != null) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestData!.statusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!), + ), + 1.width.expanded, + Text( + requestData!.transactionDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNo, value: requestData?.assetNumber, context: context), + + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: requestDetails!.status!, + textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), + backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!), + ), + 1.width.expanded, + Text( + requestDetails!.date?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 8.height, + (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context), + infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context), + infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context), + infoWidget(label: context.translation.model, value: requestDetails!.model, context: context), + 8.height, + // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.viewDetails, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)), + ), + 4.width, + Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).toShadowContainer(context, withShadow: showShadow).onPress(() async { + Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!))); + }); + } + + Widget infoWidget({required String label, String? value, required BuildContext context}) { + if (value != null && value.isNotEmpty) { + return '$label: $value'.bodyText(context); + } + return const SizedBox(); + } +} diff --git a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart index 3240bf2d..e4454551 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart @@ -15,7 +15,7 @@ class InternalAuditCheckListProvider extends LoadingListNotifier { notifyListeners(); Response response; try { - response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + response = await ApiManager.instance.get(URLs.getInternalAuditChecklist); } catch (error) { loading = false; stateCode = -1; diff --git a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart index c9ee41a8..9371cb1d 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart @@ -14,7 +14,7 @@ class InternalAuditFindingTypeProvider extends LoadingListNotifier { notifyListeners(); Response response; try { - response = await ApiManager.instance.get(URLs.getPentryTaskStatus); + response = await ApiManager.instance.get(URLs.getInternalAuditFindingType); } catch (error) { loading = false; stateCode = -1; diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 983bd6ca..6f2a9b9d 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -2,34 +2,66 @@ import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; class InternalAuditProvider extends ChangeNotifier { final pageItemNumber = 10; final searchPageItemNumber = 10; int pageNo = 1; + void reset() { pageNo = 1; stateCode = null; } + int? stateCode; bool isDetailLoading = false; bool nextPage = false; bool isNextPageLoading = false; bool isLoading = false; - Future getInternalAuditById(int id) async { + + Future getEquipmentInternalAuditById(int id) async { try { isLoading = true; notifyListeners(); - //Need to replace - Response response = await ApiManager.instance.get("${URLs.getTRAFById}?id=$id"); + Response response = await ApiManager.instance.get( + "${URLs.getInternalAuditEquipmentById}?internalAuditEquipmentId=$id", + ); if (response.statusCode >= 200 && response.statusCode < 300) { - // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); + final decodedBody = jsonDecode(response.body); + EquipmentInternalAuditDataModel model = EquipmentInternalAuditDataModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; } + } catch (error) { + isLoading = false; + notifyListeners(); + return null; + } + } + + Future getInternalSystemAuditById(int id) async { + try { + isLoading = true; + notifyListeners(); + Response response = await ApiManager.instance.get("${URLs.getInternalAuditSystemById}?AuditSystemId=$id"); + if (response.statusCode >= 200 && response.statusCode < 300) {} isLoading = false; notifyListeners(); return 0; @@ -39,4 +71,44 @@ class InternalAuditProvider extends ChangeNotifier { return -1; } } + + Future addEquipmentInternalAudit({ + required BuildContext context, + required EquipmentInternalAuditFormModel request, + }) async { + bool status = false; + Response response; + try { + response = await ApiManager.instance.post(URLs.addOrUpdateEquipmentInternalAudit, body: request.toJson()); + if (response.statusCode >= 200 && response.statusCode < 300) { + status = true; + notifyListeners(); + } else { + Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}"); + status = false; + } + return status; + } catch (error) { + print(error); + status = false; + notifyListeners(); + return status; + } + } + + Future> getWorkOrderByWoType({String? text, required int? woId}) async { + late Response response; + try { + Response response = await ApiManager.instance.get("${URLs.getWoAutoComplete}?workOrderTypeId=$woId&search=$text"); + // response = await ApiManager.instance.post(url, body: {"search": text}); + List woOrderList = []; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + woOrderList = categoriesListJson.map((wo) => WoAutoCompleteModel.fromJson(wo)).toList(); + } + return woOrderList; + } catch (error) { + return []; + } + } } diff --git a/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart new file mode 100644 index 00000000..7c7b4e5e --- /dev/null +++ b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart @@ -0,0 +1,35 @@ + +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; + +class InternalAuditWoTypeProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading ?? false) return -2; + loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getInternalAuditWoType); + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List listJson = json.decode(response.body)["data"]; + items = listJson.map((department) => Lookup.fromJson(department)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } +} + diff --git a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart index 1988336f..c88e576d 100644 --- a/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart +++ b/lib/new_views/pages/land_page/create_request-type_bottomsheet.dart @@ -9,8 +9,8 @@ import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_equipment_internal_audit_form.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart index 30f86273..2f7bf6d0 100644 --- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart +++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart @@ -58,9 +58,9 @@ class _MyRequestsPageState extends State { requestsList.add(Request(9, 'TRAF')); } if (context.userProvider.isEngineer) { - //TODO need to replace with actual number. - // requestsList.add(Request(10, 'Internal Audit')); - requestsList.add(Request(1, 'Internal Audit')); + // TODO need to replace with actual number. + requestsList.add(Request(10, 'Equipment Internal Audit')); + requestsList.add(Request(11, 'System Internal Audit')); } if (context.userProvider.isAssessor) { @@ -73,9 +73,8 @@ class _MyRequestsPageState extends State { requestsList = [ Request(null, context.translation.allWorkOrder), //TODO need to replace with actual number. - - // Request(10, 'Internal Audit'), - Request(1, 'Internal Audit'), + Request(10, 'Equipment Internal Audit'), + Request(11, 'System Internal Audit'), ]; } diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index 7b172e50..97e9bf58 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; @@ -55,7 +56,8 @@ class RequestPaginatedListview extends StatelessWidget { bool isRecurrentTask = request.transactionNo == 5; bool isTask = request.transactionNo == 6; bool isTRAF = request.transactionNo == 9; - bool isInternalAudit = request.transactionNo == 10; + bool isEquipmentInternalAudit = request.transactionNo == 10; + bool isSystemInternalAudit = request.transactionNo == 11; if (isServiceRequest) { return ServiceRequestItemView(requestData: request, refreshData: false); @@ -69,14 +71,13 @@ class RequestPaginatedListview extends StatelessWidget { return RecurrentWoItemView(requestData: request); } else if (isTask) { return TaskRequestItemView(requestData: request); - } - else if (isTRAF) { + } else if (isTRAF) { return TrafRequestItemView(requestData: request); - } - else if (isInternalAudit) { - return InternalAuditItemView(requestData: request); - } - else { + } else if (isEquipmentInternalAudit) { + return EquipmentInternalAuditItemView(requestData: request); + } else if (isSystemInternalAudit) { + return SystemInternalAuditItemView(requestData: request); + } else { return Container( height: 100, width: double.infinity, diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index 08b1f51a..ec9b9d31 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -1,12 +1,16 @@ //request tab page +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/all_requests_and_count_model.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart'; import 'package:test_sa/modules/traf_module/traf_request_item_view.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart'; import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart'; @@ -29,11 +33,19 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); + if (list[index].transactionType == null) { + return EquipmentInternalAuditItemView(requestDetails: list[index]); + // return Container( + // height: 100, + // width: double.infinity, + // color: AppColor.neutral40, + // ); + } switch (list[index].transactionType) { - // case 1: - // return ServiceRequestItemView(requestDetails: list[index]); case 1: - return InternalAuditItemView(requestDetails: list[index]); + return ServiceRequestItemView(requestDetails: list[index]); + // case 1: + // return InternalAuditItemView(requestDetails: list[index]); case 2: return GasRefillItemView(requestDetails: list[index]); case 3: @@ -48,9 +60,11 @@ class RequestItemViewList extends StatelessWidget { return TaskRequestItemView(requestDetails: list[index]); case 9: return TrafRequestItemView(requestDetails: list[index]); - //Need to verify the type No.. - case 10: - return InternalAuditItemView(requestDetails: list[index]); + //Need to verify the type No.. + case 10: + return EquipmentInternalAuditItemView(requestDetails: list[index]); + case 11: + return SystemInternalAuditItemView(requestDetails: list[index]); default: Container( height: 100, From 81dd799672c33480e3d9b5638617c30c9297fff4 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Thu, 6 Nov 2025 11:44:08 +0300 Subject: [PATCH 04/19] internal audit api's implementation in progress --- .../equipment_internal_audit_detail_page.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart index 465a42db..6d842b29 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -75,15 +75,15 @@ class _EquipmentInternalAuditDetailPageState extends State Date: Mon, 10 Nov 2025 10:33:45 +0300 Subject: [PATCH 05/19] internal audit api's implementation in progress --- lib/controllers/api_routes/urls.dart | 5 +- lib/main.dart | 4 +- .../models/audit_form_model.dart | 56 +++ .../equipment_internal_audit_data_model.dart | 10 +- .../models/internal_audit_timer_model.dart | 35 ++ .../system_internal_audit_data_model.dart | 122 +++++++ .../system_internal_audit_form_model.dart | 123 ++++++- .../equipment_internal_audit_detail_page.dart | 42 +-- .../equipment_internal_audit_item_view.dart | 1 - .../update_equipment_internal_audit_page.dart | 342 ++++++++++++++++++ .../create_system_internal_audit_form.dart | 58 +-- .../system_internal_audit_detail_page.dart | 20 +- .../system_internal_audit_item_view.dart | 1 - .../update_system_internal_audit_page.dart} | 32 +- .../provider/internal_audit_provider.dart | 65 ++++ .../tasks_wo/update_task_request_view.dart | 2 +- .../widgets/request_item_view_list.dart | 16 +- 17 files changed, 836 insertions(+), 98 deletions(-) create mode 100644 lib/modules/internal_audit_module/models/audit_form_model.dart create mode 100644 lib/modules/internal_audit_module/models/internal_audit_timer_model.dart create mode 100644 lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart create mode 100644 lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart rename lib/modules/internal_audit_module/pages/{update_internal_audit_page.dart => system_internal_audit/update_system_internal_audit_page.dart} (89%) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index dad15d8d..36d8e431 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -314,11 +314,14 @@ class URLs { //internal Audit static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; - static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2"; static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; } diff --git a/lib/main.dart b/lib/main.dart index a2f9bdca..c5b39ef2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -103,7 +103,7 @@ import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; import 'dashboard_latest/dashboard_provider.dart'; -import 'modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; import 'new_views/pages/gas_refill_request_form.dart'; import 'providers/lookups/classification_lookup_provider.dart'; @@ -365,7 +365,7 @@ class MyApp extends StatelessWidget { HelpCenterPage.id: (_) => const HelpCenterPage(), CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), - UpdateInternalAuditPage.id: (_) => const UpdateInternalAuditPage(), + UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/modules/internal_audit_module/models/audit_form_model.dart b/lib/modules/internal_audit_module/models/audit_form_model.dart new file mode 100644 index 00000000..dd3e6975 --- /dev/null +++ b/lib/modules/internal_audit_module/models/audit_form_model.dart @@ -0,0 +1,56 @@ +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class AuditFormModel { + int? id; + String? createdDate; + int? requestId; + String? debrief; + DateTime? startTime; + DateTime? endTime; + double? totalHours; + List? attachments; + bool? isComplete; + TimerModel? auditTimerModel = TimerModel(); + + AuditFormModel({ + this.id, + this.requestId, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.createdDate, + this.attachments, + this.isComplete, + this.auditTimerModel, + }); + + AuditFormModel.fromJson(Map json) { + id = json['id']; + requestId = json['requestId']; + debrief = json['debrief']; + startTime = json['startTime'] != null ? DateTime.tryParse(json['startTime']) : null; + endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null; + totalHours = json['totalHours']?.toDouble(); + if (json['attachments'] != null) { + attachments = (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .toList(); + } + isComplete = json['isComplete']; + } + + Map toJson() { + return { + 'id': id, + 'requestId': requestId, + 'debrief': debrief, + 'startTime': startTime?.toIso8601String(), + 'endTime': endTime?.toIso8601String(), + 'totalHours': totalHours, + 'attachments': attachments?.map((e) => e.toJson()).toList(), + 'isComplete': isComplete, + }; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart index 411789ec..be9c00bb 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -1,4 +1,8 @@ - class EquipmentInternalAuditDataModel { + import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; + +class EquipmentInternalAuditDataModel { int? id; String? requestNo; String? createdDate; @@ -10,7 +14,7 @@ dynamic manufacture; String? remarks; List? equipmentsFindings; - List? attachments; + List? attachments; EquipmentInternalAuditDataModel({ this.id, @@ -44,7 +48,7 @@ equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); }); } - attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + // attachments = json['attachments'] != null ? List.from(json['attachments']) : []; } Map toJson() { diff --git a/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart new file mode 100644 index 00000000..708ab2d1 --- /dev/null +++ b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart @@ -0,0 +1,35 @@ +class InternalAuditTimerModel { + int? id; + String? startDate; + String? endDate; + double? totalWorkingHour; + String? comment; + + InternalAuditTimerModel({ + this.id, + this.startDate, + this.endDate, + this.totalWorkingHour, + this.comment, + }); + + factory InternalAuditTimerModel.fromJson(Map json) { + return InternalAuditTimerModel( + id: json['id'] as int?, + startDate: json['startDate'], + endDate: json['endDate'], + totalWorkingHour: (json['totalWorkingHours'] as num?)?.toDouble(), + comment: json['comment'] as String?, + ); + } + + Map toJson() { + return { + 'id': id, + 'startDate': startDate, + 'endDate': endDate, + 'totalWorkingHours': totalWorkingHour, + 'comment': comment, + }; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart new file mode 100644 index 00000000..ae84e97f --- /dev/null +++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart @@ -0,0 +1,122 @@ +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; + +class SystemInternalAuditDataModel { + int? id; + int? assetGroupId; + String? requestNo; + int? requestNoSequence; + Auditor? auditor; + Lookup? status; + Lookup? findingType; + String? findingDescription; + Lookup? workOrderType; + Auditor? assignEmployee; + SystemAuditWorkOrderDetailModel? workOrderDetails; // Already exists as a separate model + String? createdBy; + String? createdDate; + String? modifiedBy; + String? modifiedDate; + + SystemInternalAuditDataModel({ + this.id, + this.assetGroupId, + this.requestNo, + this.requestNoSequence, + this.auditor, + this.status, + this.findingType, + this.findingDescription, + this.workOrderType, + this.assignEmployee, + this.workOrderDetails, + this.createdBy, + this.createdDate, + this.modifiedBy, + this.modifiedDate, + }); + + SystemInternalAuditDataModel.fromJson(Map json) { + id = json['id']; + assetGroupId = json['assetGroupId']; + requestNo = json['requestNo']; + requestNoSequence = json['requestNoSequence']; + auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null; + status = json['status'] != null ? Lookup.fromJson(json['status']) : null; + findingType = json['findingType'] != null ? Lookup.fromJson(json['findingType']) : null; + findingDescription = json['findingDescription']; + workOrderType = json['workOrderType'] != null ? Lookup.fromJson(json['workOrderType']) : null; + assignEmployee = json['assignEmployee'] != null ? Auditor.fromJson(json['assignEmployee']) : null; + workOrderDetails = json['workOrderDetails'] != null ? SystemAuditWorkOrderDetailModel.fromJson(json['workOrderDetails']) : null; // Keep as-is + createdBy = json['createdBy']; + createdDate = json['createdDate']; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['assetGroupId'] = assetGroupId; + data['requestNo'] = requestNo; + data['requestNoSequence'] = requestNoSequence; + if (auditor != null) data['auditor'] = auditor!.toJson(); + if (status != null) data['status'] = status!.toJson(); + if (findingType != null) data['findingType'] = findingType!.toJson(); + data['findingDescription'] = findingDescription; + if (workOrderType != null) data['workOrderType'] = workOrderType!.toJson(); + if (assignEmployee != null) data['assignEmployee'] = assignEmployee!.toJson(); + data['workOrderDetails'] = workOrderDetails; + data['createdBy'] = createdBy; + data['createdDate'] = createdDate; + data['modifiedBy'] = modifiedBy; + data['modifiedDate'] = modifiedDate; + return data; + } +} + +class Auditor { + String? userId; + String? userName; + String? email; + String? employeeId; + int? languageId; + String? extensionNo; + String? phoneNumber; + bool? isActive; + + Auditor({ + this.userId, + this.userName, + this.email, + this.employeeId, + this.languageId, + this.extensionNo, + this.phoneNumber, + this.isActive, + }); + + Auditor.fromJson(Map json) { + userId = json['userId']; + userName = json['userName']; + email = json['email']; + employeeId = json['employeeId']; + languageId = json['languageId']; + extensionNo = json['extensionNo']; + phoneNumber = json['phoneNumber']; + isActive = json['isActive']; + } + + Map toJson() { + final Map data = {}; + data['userId'] = userId; + data['userName'] = userName; + data['email'] = email; + data['employeeId'] = employeeId; + data['languageId'] = languageId; + data['extensionNo'] = extensionNo; + data['phoneNumber'] = phoneNumber; + data['isActive'] = isActive; + return data; + } +} diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart index 9750e9e0..4082eb03 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -4,7 +4,7 @@ import 'dart:developer'; import 'package:test_sa/models/lookup.dart'; class SystemInternalAuditFormModel { - int? id = 0; + int? id; String? auditorId; String? assignEmployeeId; Lookup? findingType; @@ -18,6 +18,7 @@ class SystemInternalAuditFormModel { int? gasRefillId; int? planRecurrentTaskId; int? statusId; + SystemAuditWorkOrderDetailModel ?workOrderDetailModel; SystemInternalAuditFormModel({ this.id, @@ -33,12 +34,13 @@ class SystemInternalAuditFormModel { this.taskAlertJobId, this.gasRefillId, this.planRecurrentTaskId, + this.workOrderDetailModel, this.statusId, }); Map toJson() { return { - 'id': id, + // 'id': id, 'auditorId': auditorId, 'assignEmployeeId': assignEmployeeId, 'findingTypeId': findingType?.id, @@ -77,6 +79,123 @@ class WoAutoCompleteModel { return data; } } +class SystemAuditWorkOrderDetailModel { + String? createdBy; + DateTime? createdDate; + String? modifiedBy; + DateTime? modifiedDate; + int? id; + String? workOrderNo; + String? woAssignedEngineer; + String? woAssetNo; + String? wosn; + String? woAssetName; + String? woModel; + String? woManufacturer; + String? woSite; + String? woDepartment; + String? wOPMScheduleDate; + String? wOPMActualVisitDate; + String? wOAssetTransferDestinationSite; + String? wOAssetTransferSenderEngineer; + String? wOAssetTransferReceiverEngineer; + String? wOTaskAlertJobImpactedStatus; + String? wOTaskAlertJobAcknowledgment; + String? wOGasRefillType; + String? wORecurrentTaskTaskType; + String? wORecurrentTaskPlanNo; + String? wORecurrentTaskPlanName; + String? wORecurrentTaskStatus; + + SystemAuditWorkOrderDetailModel({ + this.createdBy, + this.createdDate, + this.modifiedBy, + this.modifiedDate, + this.id, + this.workOrderNo, + this.woAssignedEngineer, + this.woAssetNo, + this.wosn, + this.woAssetName, + this.woModel, + this.woManufacturer, + this.woSite, + this.woDepartment, + this.wOPMScheduleDate, + this.wOPMActualVisitDate, + this.wOAssetTransferDestinationSite, + this.wOAssetTransferSenderEngineer, + this.wOAssetTransferReceiverEngineer, + this.wOTaskAlertJobImpactedStatus, + this.wOTaskAlertJobAcknowledgment, + this.wOGasRefillType, + this.wORecurrentTaskTaskType, + this.wORecurrentTaskPlanNo, + this.wORecurrentTaskPlanName, + this.wORecurrentTaskStatus, + }); + + SystemAuditWorkOrderDetailModel.fromJson(Map json) { + createdBy = json['createdBy']; + createdDate = json['createdDate'] != null ? DateTime.tryParse(json['createdDate']) : null; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate'] != null ? DateTime.tryParse(json['modifiedDate']) : null; + id = json['id']; + workOrderNo = json['workOrderNo']; + woAssignedEngineer = json['woAssignedEngineer']; + woAssetNo = json['woAssetNo']; + wosn = json['wosn']; + woAssetName = json['woAssetName']; + woModel = json['woModel']; + woManufacturer = json['woManufacturer']; + woSite = json['woSite']; + woDepartment = json['woDepartment']; + wOPMScheduleDate = json['wO_PM_ScheduleDate']; + wOPMActualVisitDate = json['wO_PM_ActualVisitDate']; + wOAssetTransferDestinationSite = json['wO_AssetTransfer_DestinationSite']; + wOAssetTransferSenderEngineer = json['wO_AssetTransfer_SenderEngineer']; + wOAssetTransferReceiverEngineer = json['wO_AssetTransfer_ReceiverEngineer']; + wOTaskAlertJobImpactedStatus = json['wO_TaskAlertJob_ImpactedStatus']; + wOTaskAlertJobAcknowledgment = json['wO_TaskAlertJob_Acknowledgment']; + wOGasRefillType = json['wO_GasRefill_Type']; + wORecurrentTaskTaskType = json['wO_RecurrentTask_TaskType']; + wORecurrentTaskPlanNo = json['wO_RecurrentTask_PlanNo']; + wORecurrentTaskPlanName = json['wO_RecurrentTask_PlanName']; + wORecurrentTaskStatus = json['wO_RecurrentTask_Status']; + } + + Map toJson() { + return { + 'createdBy': createdBy, + 'createdDate': createdDate?.toIso8601String(), + 'modifiedBy': modifiedBy, + 'modifiedDate': modifiedDate?.toIso8601String(), + 'id': id, + 'workOrderNo': workOrderNo, + 'woAssignedEngineer': woAssignedEngineer, + 'woAssetNo': woAssetNo, + 'wosn': wosn, + 'woAssetName': woAssetName, + 'woModel': woModel, + 'woManufacturer': woManufacturer, + 'woSite': woSite, + 'woDepartment': woDepartment, + 'wO_PM_ScheduleDate': wOPMScheduleDate, + 'wO_PM_ActualVisitDate': wOPMActualVisitDate, + 'wO_AssetTransfer_DestinationSite': wOAssetTransferDestinationSite, + 'wO_AssetTransfer_SenderEngineer': wOAssetTransferSenderEngineer, + 'wO_AssetTransfer_ReceiverEngineer': wOAssetTransferReceiverEngineer, + 'wO_TaskAlertJob_ImpactedStatus': wOTaskAlertJobImpactedStatus, + 'wO_TaskAlertJob_Acknowledgment': wOTaskAlertJobAcknowledgment, + 'wO_GasRefill_Type': wOGasRefillType, + 'wO_RecurrentTask_TaskType': wORecurrentTaskTaskType, + 'wO_RecurrentTask_PlanNo': wORecurrentTaskPlanNo, + 'wO_RecurrentTask_PlanName': wORecurrentTaskPlanName, + 'wO_RecurrentTask_Status': wORecurrentTaskStatus, + }; + } +} diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart index 6d842b29..5d788a6f 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart @@ -9,13 +9,13 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; -import 'package:test_sa/modules/internal_audit_module/pages/update_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class EquipmentInternalAuditDetailPage extends StatefulWidget { static const String id = "/details-internal-audit"; @@ -62,7 +62,8 @@ class _EquipmentInternalAuditDetailPageState extends State provider.isLoading, builder: (_, isLoading, __) { if (isLoading) return const ALoading(); - return Column( + if (model==null) return NoDataFound(message: context.translation.noDataFound).center; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( @@ -74,25 +75,24 @@ class _EquipmentInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + //TODO need to check for attachments backend need to fix the name they are sending wrong string + // if (model!.attachments!.isNotEmpty) ...[ + // const Divider().defaultStyle(context), + // Text( + // "Attachments".addTranslation, + // style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + // ), + // 8.height, + // FilesList(images: model!.attachments!.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), // ], ], ).paddingAll(0).toShadowContainer(context), @@ -104,7 +104,7 @@ class _EquipmentInternalAuditDetailPageState extends State UpdateEquipmentInternalAuditPage(model: model))); }), ), ], diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart index 4c4bbb57..a17407a2 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart @@ -22,7 +22,6 @@ class EquipmentInternalAuditItemView extends StatelessWidget { @override Widget build(BuildContext context) { //TODO need to refactor this code repetation @waseem - log('request details ${requestDetails?.toJson()}'); if (requestData != null) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart new file mode 100644 index 00000000..02115d62 --- /dev/null +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -0,0 +1,342 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; +import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart'; + +class UpdateEquipmentInternalAuditPage extends StatefulWidget { + static const String id = "update-equipment-internal-audit"; + EquipmentInternalAuditDataModel? model; + + UpdateEquipmentInternalAuditPage({Key? key,this.model}) : super(key: key); + + @override + State createState() => _UpdateEquipmentInternalAuditPageState(); +} + +class _UpdateEquipmentInternalAuditPageState extends State { + final bool _isLoading = false; + double totalWorkingHours = 0.0; + AuditFormModel formModel = AuditFormModel(); + final TextEditingController _workingHoursController = TextEditingController(); + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + List _attachments = []; + //TODO need to check if it's needed or not.. + List timerList = []; + + @override + void initState() { + populateForm(); + super.initState(); + } + void populateForm(){ + formModel.requestId = widget.model?.id; + formModel.id = widget.model?.id; + _attachments = widget.model?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? []; + + } + void calculateWorkingTime() { + // final timers = _formModel.gasRefillTimers ?? []; + // totalWorkingHours = timers.fold(0.0, (sum, item) { + // if (item.startDate == null || item.endDate == null) return sum; + // try { + // final start = DateTime.parse(item.startDate!); + // final end = DateTime.parse(item.endDate!); + // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + // return sum + diffInHours; + // } catch (_) { + // return sum; + // } + // }); + // + // timerList = timers.map((e) { + // return TimerHistoryModel( + // id: e.id, + // startTime: e.startDate, + // endTime: e.endDate, + // workingHours: e.workingHours, + // ); + // }).toList(); + } + + + _onSubmit(BuildContext context) async { + bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + InternalAuditProvider provider = Provider.of(context,listen: false); + + _formKey.currentState!.save(); + formModel.attachments = []; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') + ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") + : item.name ?? ''; + formModel.attachments!.add( + InternalAuditAttachments( + id: item.id, + originalName: fileName, + // name: fileName, + ), + ); + } + provider.updateEquipmentInternalAudit(model: formModel); + + log('payload ${formModel.toJson()}'); + + + + // if (isTimerPickerEnable) { + // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.gasRefillTimePicker == null) { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // } else { + // if (_formModel.timer?.startAt == null) { + // Fluttertoast.showToast(msg: "Working Hours Required"); + // return false; + // } + // if (_formModel.timer?.endAt == null) { + // Fluttertoast.showToast(msg: "Please Stop The Timer"); + // return false; + // } + // } + // + // if (_currentDetails.deliverdQty == null) { + // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); + // return false; + // } + // _formModel.gasRefillDetails = []; + // _formModel.gasRefillDetails?.add(_currentDetails); + // + // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; + // if (_formModel.gasRefillTimePicker != null) { + // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null + // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // } + // _formModel.timerModelList?.forEach((timer) { + // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + // _formModel.gasRefillTimers?.add( + // GasRefillTimer( + // id: 0, + // startDate: timer.startAt!.toIso8601String(), // Handle potential null + // endDate: timer.endAt?.toIso8601String(), // Handle potential null + // workingHours: ((durationInSecond) / 60 / 60), + // ), + // ); + // }); + // _formModel.gasRefillAttachments = []; + // for (var item in _attachments) { + // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; + // _formModel.gasRefillAttachments?.add(GasRefillAttachments( + // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); + // } + + // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { + // Navigator.pop(context); + // if (success) { + // if (status == 1) { + // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); + // // when click complete then this request remove from the list and status changes to closed.. + // _gasRefillProvider?.reset(); + // allRequestsProvider.getAllRequests(context, typeTransaction: 2); + // } + // Navigator.pop(context); + // } + // }); + } + + @override + void dispose() { + _workingHoursController.dispose(); + super.dispose(); + } + + void updateTimer({TimerModel? timer}) { + if (timer?.startAt != null && timer?.endAt != null) { + final start = timer!.startAt!; + final end = timer.endAt!; + + final difference = end.difference(start); + final totalHours = difference.inSeconds / 3600.0; + formModel.startTime = start; + formModel.endTime = end; + formModel.totalHours = totalHours; + } + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: DefaultAppBar( + title: 'Update Information'.addTranslation, + onWillPopScope: () { + formModel.isComplete = false; + _onSubmit(context); + }, + ), + key: _scaffoldKey, + body: Form( + key: _formKey, + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + AppTextFormField( + labelText: 'Debrief'.addTranslation, + textInputType: TextInputType.multiline, + hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), + alignLabelWithHint: true, + initialValue: formModel.debrief, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + onSaved: (value) { + formModel.debrief = value; + }, + ), + 8.height, + _timerWidget(context, totalWorkingHours), + 16.height, + AttachmentPicker( + label: context.translation.attachFiles, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset( + color: AppColor.primary10, + ), + ), + 8.height, + ], + ).toShadowContainer(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + AppFilledButton( + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: (){ + formModel.isComplete = false; + _onSubmit(context); + } + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: (){ + formModel.isComplete = true; + _onSubmit(context); + } + ).expanded, + ], + ), + ), + ], + )), + ), + ).handlePopScope( + cxt: context, + onSave: () { + formModel.isComplete=false; + _onSubmit(context); + }); + } + + Widget _timerWidget(BuildContext context, double totalWorkingHours) { + TimerModel? timer = TimerModel(); + TimerModel? timerPicker; + List? timerModelList = []; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppTimer( + label: context.translation.workingHours, + timer: timer, + pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + pickerTimer: timerPicker, + onPick: (time) { + updateTimer(timer: timer); + + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + log('here onChange ${timer.startAt}'); + + return true; + }, + ), + if (totalWorkingHours > 0.0) ...[ + 12.height, + WorkingTimeTile( + timerList: timerList, + totalWorkingTime: totalWorkingHours, + ), + ], + ], + ); + } +} diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index 64e8408b..a443588d 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -91,7 +91,8 @@ class _CreateSystemInternalAuditFormState extends State(context, listen: false); + setState(() { + showLoading = true; + }); + _model.workOrderDetailModel = await provider.loadAllWorkOrderDetailsByID(workOrderId: wo.id!, workOrderTypeId: _model.workOrderType!.value!); + updateWorkOrderReference(woTypeId: _model.workOrderType?.value, selectedId: wo.id); + + setState(() { + showLoading = false; + }); }, ), 12.height, @@ -166,14 +175,16 @@ class _CreateSystemInternalAuditFormState extends State _submit() async { + InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); - List attachement = []; - for (var item in _deviceImages) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - // attachement.add(WorkOrderAttachments(id: 0, name: fileName)); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + _model.auditorId = context.userProvider.user?.userID; + bool status = await internalAuditProvider.addSystemInternalAudit(context: context, request: _model); + Navigator.pop(context); + if (status) { + Navigator.pop(context); } - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); } } @@ -193,7 +204,7 @@ class _CreateSystemInternalAuditFormState extends State { bool isWoType = true; + // EquipmentInternalAuditDataModel? model; + late InternalAuditProvider _internalAuditProvider; @override void initState() { super.initState(); - //TODO need to get and assign data . - // Provider.of(context, listen: false).getInternalAuditById(widget.auditId); + _internalAuditProvider = Provider.of(context, listen: false); + WidgetsBinding.instance.addPostFrameCallback((_) { + getAuditData(); + }); + } + + Future getAuditData() async { + await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); } @override @@ -69,7 +77,7 @@ class _SystemInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), @@ -94,7 +102,7 @@ class _SystemInternalAuditDetailPageState extends State { final bool _isLoading = false; double totalWorkingHours = 0.0; late UserProvider _userProvider; - - // GasRefillDetails _currentDetails = GasRefillDetails(); final TextEditingController _commentController = TextEditingController(); final TextEditingController _workingHoursController = TextEditingController(); - - // final GasRefillModel _formModel = GasRefillModel(gasRefillDetails: []); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); bool _firstTime = true; @@ -51,18 +49,6 @@ class _UpdateInternalAuditPageState extends State { @override void initState() { super.initState(); - // if (widget.gasRefillModel != null) { - // _formModel.fromGasRefillModel(widget.gasRefillModel!); - // _commentController.text = _formModel.techComment ?? ""; - // calculateWorkingTime(); - // try { - // _deliveredQuantity = deliveredQuantity.singleWhere((element) => element.value == _formModel.gasRefillDetails![0].deliverdQty); - // _currentDetails.deliverdQty = _deliveredQuantity!.value; - // } catch (ex) {} - // } - // if (_formModel.gasRefillAttachments != null && _formModel.gasRefillAttachments!.isNotEmpty) { - // _attachments.addAll(_formModel.gasRefillAttachments!.map((e) => GenericAttachmentModel(id:e.id,name:e.attachmentName!)).toList()); - // } } void calculateWorkingTime() { @@ -194,16 +180,6 @@ class _UpdateInternalAuditPageState extends State { @override Widget build(BuildContext context) { _userProvider = Provider.of(context); - if (_firstTime) { - String? clientName; - // if (widget.gasRefillModel != null) { - // _gasRefillProvider!.expectedDateTime = DateTime.tryParse(_formModel.expectedDate ?? ""); - // _formModel.timer = TimerModel(startAt: DateTime.tryParse(widget.gasRefillModel?.startDate ?? ""), endAt: DateTime.tryParse(widget.gasRefillModel?.endDate ?? "")); - // } else { - // _formModel.timer = null; - // } - } - return Scaffold( appBar: DefaultAppBar( title: 'Update Information'.addTranslation, diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 6f2a9b9d..314fb2d9 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; @@ -71,6 +72,47 @@ class InternalAuditProvider extends ChangeNotifier { return -1; } } + Future loadAllWorkOrderDetailsByID({required int workOrderTypeId,required int workOrderId}) async { + try { + isLoading = true; + notifyListeners(); + Response response = await ApiManager.instance.get("${URLs.loadAllWorkOrderDetailsByID}?workOrderTypeId=$workOrderTypeId&workOrderId=$workOrderId"); + if (response.statusCode >= 200 && response.statusCode < 300) { + final decodedBody = jsonDecode(response.body); + SystemAuditWorkOrderDetailModel model = SystemAuditWorkOrderDetailModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } + } catch (error) { + isLoading = false; + notifyListeners(); + return null; + } + } + Future updateEquipmentInternalAudit({required AuditFormModel model}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.put(URLs.updateAuditEquipmentsEngineer, body: model.toJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + if (stateCode == 200) { + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } Future addEquipmentInternalAudit({ required BuildContext context, @@ -95,6 +137,29 @@ class InternalAuditProvider extends ChangeNotifier { return status; } } + Future addSystemInternalAudit({ + required BuildContext context, + required SystemInternalAuditFormModel request, + }) async { + bool status = false; + Response response; + try { + response = await ApiManager.instance.post(URLs.addOrUpdateInternalAuditSystem, body: request.toJson()); + if (response.statusCode >= 200 && response.statusCode < 300) { + status = true; + notifyListeners(); + } else { + Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}"); + status = false; + } + return status; + } catch (error) { + print(error); + status = false; + notifyListeners(); + return status; + } + } Future> getWorkOrderByWoType({String? text, required int? woId}) async { late Response response; diff --git a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart index d25049df..40871d70 100644 --- a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart @@ -271,7 +271,7 @@ class _UpdateTaskRequestState extends State { taskModel?.timerModelList?.forEach((timer) { int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( - TaskJobActivityEngineerTimer( + TaskJobActivityEngineerTimer ( id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments), ); }); diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart index ec9b9d31..54639c40 100644 --- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart +++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart @@ -33,14 +33,14 @@ class RequestItemViewList extends StatelessWidget { shrinkWrap: true, itemBuilder: (cxt, index) { if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); - if (list[index].transactionType == null) { - return EquipmentInternalAuditItemView(requestDetails: list[index]); - // return Container( - // height: 100, - // width: double.infinity, - // color: AppColor.neutral40, - // ); - } + // if (list[index].transactionType == null) { + // return EquipmentInternalAuditItemView(requestDetails: list[index]); + // // return Container( + // // height: 100, + // // width: double.infinity, + // // color: AppColor.neutral40, + // // ); + // } switch (list[index].transactionType) { case 1: return ServiceRequestItemView(requestDetails: list[index]); From 3d2e90861382b61ab2d54e63447ffe6ae3d35d08 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 10 Nov 2025 14:43:29 +0300 Subject: [PATCH 06/19] traf form validation added. --- .../traf_module/create_traf_request_page.dart | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart index 69756285..05670e01 100644 --- a/lib/modules/traf_module/create_traf_request_page.dart +++ b/lib/modules/traf_module/create_traf_request_page.dart @@ -165,6 +165,10 @@ class _CreateTRAFRequestPageState extends State { AppTextFormField( initialValue: "", labelText: "How would the requested technology solve the current situation and/or serve the purpose?", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), @@ -178,6 +182,10 @@ class _CreateTRAFRequestPageState extends State { AppTextFormField( initialValue: "", labelText: "What is the current practice?", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), showShadow: false, @@ -191,6 +199,10 @@ class _CreateTRAFRequestPageState extends State { initialValue: "", makeMultiLinesNull: true, labelText: "Census Q1", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), showShadow: false, @@ -204,6 +216,10 @@ class _CreateTRAFRequestPageState extends State { initialValue: "", makeMultiLinesNull: true, labelText: "Census Q2", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), showShadow: false, @@ -217,6 +233,10 @@ class _CreateTRAFRequestPageState extends State { initialValue: "", makeMultiLinesNull: true, labelText: "Census Q3", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), showShadow: false, @@ -230,6 +250,10 @@ class _CreateTRAFRequestPageState extends State { initialValue: "", makeMultiLinesNull: true, labelText: "Census Q4", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), showShadow: false, @@ -347,6 +371,10 @@ class _CreateTRAFRequestPageState extends State { textInputType: TextInputType.multiline, alignLabelWithHint: true, node: otherServicesEffectsNode, + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, labelText: "List down these services and stat how would it be effected", backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), @@ -384,6 +412,10 @@ class _CreateTRAFRequestPageState extends State { textInputType: TextInputType.multiline, alignLabelWithHint: true, node: useInCombinationNode, + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, labelText: "kindly describe in detail", backgroundColor: AppColor.fieldBgColor(context), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), @@ -430,11 +462,32 @@ class _CreateTRAFRequestPageState extends State { } void _verifyAndSubmit() async { + if (requestType == null) { + "Select request type".showToast; + return; + } else if (requestType?.value == 1 && trafRequest?.assetNDId == null) { + "Oracle Code missing".showToast; + return; + } else if (requestType?.value == 2 && trafRequest?.assetId == null) { + "Pick asset".showToast; + return; + } + if (!_formKey.currentState!.validate()) return; + trafRequest?.employeeId = context.userProvider.user?.userID; trafRequest?.siteId = context.userProvider.user?.clientId; trafRequest?.trafContacts = []; trafRequest?.trafContacts = userBasedOnSearch.map((item) => TrafContacts(id: 0, trafId: 0, name: item.userName, userId: item.userId)).toList(); + if ((trafRequest?.trafContacts ?? []).isEmpty) { + "Please specify users going to use technology".showToast; + return; + } + if (isUsedSolelyOrShared?.value == 1 && (trafRequest?.trafDepartments ?? []).isEmpty) { + "Please specify departments and relations".showToast; + return; + } + Utils.showLoading(context); bool isSuccess = await Provider.of(context, listen: false).addTraf(trafRequest!.toJson()); Utils.hideLoading(context); From c1455378a62921c59336eb12ee11e6b9c7a6cb3c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Mon, 10 Nov 2025 16:15:06 +0300 Subject: [PATCH 07/19] bug fixes and improvements --- assets/images/collesped_arrow_icon.svg | 3 + assets/images/expended_arrow_icon.svg | 3 + lib/controllers/api_routes/urls.dart | 1 + .../models/asset_inventory_model.dart | 50 ++++- .../pages/asset_detail_card_view.dart | 138 ++++++------- .../pages/asset_inventory_detail_view.dart | 195 ++++++++++++------ .../pages/asset_inventory_form_view.dart | 49 ++--- .../pages/asset_inventory_page.dart | 2 +- .../pages/inventory_session_item_view.dart | 12 -- pubspec.lock | 8 + pubspec.yaml | 1 + 11 files changed, 290 insertions(+), 172 deletions(-) create mode 100644 assets/images/collesped_arrow_icon.svg create mode 100644 assets/images/expended_arrow_icon.svg diff --git a/assets/images/collesped_arrow_icon.svg b/assets/images/collesped_arrow_icon.svg new file mode 100644 index 00000000..7980fef7 --- /dev/null +++ b/assets/images/collesped_arrow_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/expended_arrow_icon.svg b/assets/images/expended_arrow_icon.svg new file mode 100644 index 00000000..c1085125 --- /dev/null +++ b/assets/images/expended_arrow_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 72f82b54..c2f40b8c 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -8,6 +8,7 @@ class URLs { // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url + // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT diff --git a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart index 0b6796cb..4a4e6587 100644 --- a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart +++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart @@ -100,13 +100,13 @@ class AssetInventoryModel { String? photo; String? photoOriginName; String? remarks; - Site? site; Building? building; Floor? floor; Department? department; Rooms? room; SupplierDetails? supplier; + List assetInventoryDetailAssetAttachments = []; AssetInventoryModel({ this.id, @@ -160,6 +160,7 @@ class AssetInventoryModel { this.floor, this.room, this.supplier, + this.assetInventoryDetailAssetAttachments = const [], }); AssetInventoryModel.fromJson(Map json) { @@ -194,6 +195,13 @@ class AssetInventoryModel { photo = json['photo']; photoOriginName = json['photoOriginName']; remarks = json['remarks']; + if (json['assetTransferAttachments'] != null) { + assetInventoryDetailAssetAttachments = []; + json['assetInventoryDetailAssetAttachments'].forEach((v) { + assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v)); + }); + } + //new data.. // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber']; // manufacturerId = json['manufacturerId'] ?? json['manufacturerId']; @@ -232,6 +240,9 @@ class AssetInventoryModel { 'newSupplierName': newSupplierName, 'photo': photo, 'remarks': remarks, + 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null + ? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList() + : [], }; } @@ -290,8 +301,45 @@ class AssetInventoryModel { department: department ?? other.department, room: room ?? other.room, supplier: supplier ?? other.supplier, + assetInventoryDetailAssetAttachments: assetInventoryDetailAssetAttachments??other.assetInventoryDetailAssetAttachments, ); } } +class AssetInventoryDetailAssetAttachments { + AssetInventoryDetailAssetAttachments({ + this.id, + this.name, + this.originalName, + }); + + AssetInventoryDetailAssetAttachments.fromJson(dynamic json) { + id = json['id']; + name = json['name']; + originalName = json['originalName']; + } + + num? id; + String? name; + String? originalName; + + AssetInventoryDetailAssetAttachments copyWith({ + num? id, // Parameter is now nullable + String? name, // Parameter is now nullable + String? originalName, // Parameter is now nullable + }) => + AssetInventoryDetailAssetAttachments( + id: id ?? this.id, + name: name??this.name, + originalName: originalName??this.originalName, + ); + + Map toJson() { + final map = {}; + map['id'] = id; + map['name'] = name; + map['originalName'] = originalName; + return map; + } +} diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart index c49a836f..2bb74028 100644 --- a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -24,6 +24,7 @@ class AssetDetailCardView extends StatelessWidget { @override Widget build(BuildContext context) { return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ @@ -37,81 +38,72 @@ class AssetDetailCardView extends StatelessWidget { ], ), 8.height, - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'transaction Date: ${assetInventoryModel.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.model}: ${assetInventoryModel.model ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${'Classifications'.addTranslation}: ${assetInventoryModel.status ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - Text( - '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}', - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), - ], - ).expanded, - Container( - decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), - height: 115.toScreenHeight, - width: 115.toScreenWidth, - margin: const EdgeInsets.only(top: 8), - child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty - ? ClipRRect( - borderRadius: BorderRadius.circular(8), - child: ImageLoader( - url: URLs.getFileUrl(assetInventoryModel.photo), - boxFit: BoxFit.cover, - height: 48, - width: 48, - )) - : 'image_placeholder'.toSvgAsset().center, - ) - ], + Text( + 'Inventory Date: ${assetInventoryModel.transactionDate?.toServiceRequestDetailsFormat ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.model}: ${assetInventoryModel.model ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'Classifications'.addTranslation}: ${assetInventoryModel.status ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), + Text( + '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), ], ).toShadowContainer(context, borderRadius: 20, padding: 12); } } +//TODO old code. +// Container( +// decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), +// height: 115.toScreenHeight, +// width: 115.toScreenWidth, +// margin: const EdgeInsets.only(top: 8), +// child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty +// ? ClipRRect( +// borderRadius: BorderRadius.circular(8), +// child: ImageLoader( +// url: URLs.getFileUrl(assetInventoryModel.photo), +// boxFit: BoxFit.cover, +// height: 48, +// width: 48, +// )) +// : 'image_placeholder'.toSvgAsset().center, +// ) diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart index 5c826f56..9337013a 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart @@ -4,6 +4,7 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -48,12 +49,15 @@ class _AssetInventoryDetailViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + // StatusLabel( label: sessionModel.statusName, id: sessionModel.statusId, radius: 4, - textColor: AppColor.green15, - backgroundColor: AppColor.greenStatus(context), + textColor: AppColor.getRequestStatusTextColorByName(context, sessionModel.statusName), + backgroundColor: AppColor.getRequestStatusColorByName(context, sessionModel.statusName), + // textColor: AppColor.green15, + // backgroundColor: AppColor.greenStatus(context), ), Text( sessionModel.createdDate!.toString().toServiceRequestCardFormat, @@ -64,7 +68,7 @@ class _AssetInventoryDetailViewState extends State { ), 8.height, Text( - context.translation.requestDetails, + 'Session Details'.addTranslation, style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), 8.height, @@ -100,64 +104,139 @@ class _AssetInventoryDetailViewState extends State { style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), 8.height, - ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - padding: EdgeInsets.zero, - itemCount: sites.length, - itemBuilder: (cxt, siteIndex) { - final site = sites[siteIndex]; - final buildingNames = (site.buildings ?? []).map((b) => b.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); - final floorNames = (site.buildings ?? []).expand((b) => b.floors ?? []).map((f) => f.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); - final departmentNames = - (site.buildings ?? []).expand((b) => b.floors ?? []).expand((f) => f.departments ?? []).map((d) => d.name).where((name) => name != null && name!.trim().isNotEmpty).join(', '); - final roomNames = (site.buildings ?? []) - .expand((b) => b.floors ?? []) - .expand((f) => f.departments ?? []) - .expand((d) => d.rooms ?? []) - .map((r) => r.name) - .where((name) => name != null && name!.trim().isNotEmpty) - .join(', '); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + SiteHierarchyView( + sites: sites, + ), + ], + ).toShadowContainer(context, padding: 12, borderRadius: 20); + } +} + + + +class SiteHierarchyView extends StatelessWidget { + final List sites; + + const SiteHierarchyView({super.key, required this.sites}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: sites.length, + itemBuilder: (context, index) { + final site = sites[index]; + return HierarchyTile( + title: site.name ?? '-', + children: (site.buildings ?? []) + .map((b) => HierarchyTile( + title: b.name ?? '-', + children: (b.floors ?? []) + .map((f) => HierarchyTile( + title: f.name ?? '-', + children: (f.departments ?? []) + .map((d) => HierarchyTile( + title: d.name ?? '-', + children: (d.rooms ?? []) + .map((r) => LeafTile(title: r.name ?? '-')) + .toList(), + )) + .toList(), + )) + .toList(), + )) + .toList(), + ); + }, + ); + } +} +class HierarchyTile extends StatefulWidget { + final String title; + final List children; + final double indent; + + const HierarchyTile({ + super.key, + required this.title, + this.children = const [], + this.indent = 0, + }); + + @override + State createState() => _HierarchyTileState(); +} + +class _HierarchyTileState extends State { + bool expanded = false; + + @override + Widget build(BuildContext context) { + final hasChildren = widget.children.isNotEmpty; + return Padding( + padding: EdgeInsets.only(left: widget.indent,top: 10.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: hasChildren ? () => setState(() => expanded = !expanded) : null, + child: Row( children: [ + if (hasChildren) + // expanded? 'expended_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13): 'collesped_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13) + Icon( + expanded ? Icons.expand_more : Icons.chevron_right, + size: 25.toScreenHeight, + color: AppColor.neutral50, + ) + else + SizedBox(width: 18.toScreenWidth), + SizedBox(width: 15.toScreenWidth), Text( - site.name ?? '-', - style: AppTextStyles.heading6.copyWith( - color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, - ), - ), - Text( - '${context.translation.building}: ${buildingNames.isNotEmpty ? buildingNames : '-'}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), - ), - Text( - '${context.translation.floor}: ${floorNames.isNotEmpty ? floorNames : '-'}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), - ), - Text( - '${context.translation.department}: ${departmentNames.isNotEmpty ? departmentNames : '-'}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), - ), - Text( - '${context.translation.room}: ${roomNames.isNotEmpty ? roomNames : '-'}', - style: AppTextStyles.bodyText.copyWith( - color: context.isDark ? AppColor.neutral10 : AppColor.neutral120, - ), + widget.title, + style:AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), ), ], - ); - }, - separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), - ), - ], - ).toShadowContainer(context, padding: 12, borderRadius: 20); + ), + ), + if (expanded) + Padding( + padding: const EdgeInsets.only(left: 20, top: 6), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: widget.children + .map((child) => child is HierarchyTile + ? HierarchyTile( + title: (child).title, + indent: 0, + children: (child).children, + ) + : child) + .toList(), + ), + ), + ], + ), + ); + } +} +class LeafTile extends StatelessWidget { + final String title; + + const LeafTile({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 22, top: 4, bottom: 4), + child: Text( + title, + style: const TextStyle(fontSize: 13, color: Colors.black87), + ), + ); } } + + diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart index fd4bea7c..f6c2e0b2 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart @@ -294,30 +294,17 @@ class _AssetInventoryFormViewState extends State { ], 12.height, Text( - 'Asset Photo'.addTranslation, + 'Attachments'.addTranslation, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936), ), 12.height, - attachments.isEmpty - ? AttachmentPicker( - label: context.translation.attachImage, - attachment: attachments, - buttonColor: AppColor.black10, - onlyImages: true, - onChange: (value) { - setState(() {}); - }, - buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), - ) - : MultiFilesPickerItem( - file: File(attachments.first.name ?? ''), - enabled: true, - onRemoveTap: (file) { - setState(() { - attachments.clear(); - }); - }, - ), + AttachmentPicker( + label: context.translation.attachFiles, + attachment: attachments, + buttonColor: AppColor.black10, + onlyImages: false, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120), + ), 12.height, AppTextFormField( backgroundColor: AppColor.fieldBgColor(context), @@ -338,7 +325,7 @@ class _AssetInventoryFormViewState extends State { .expanded, FooterActionButton.footerContainer( context: context, - child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit), + child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Submit'.addTranslation, maxWidth: true, onPressed: _onSubmit), ), ], ), @@ -348,7 +335,6 @@ class _AssetInventoryFormViewState extends State { Future searchAsset({required String assetNo}) async { AssetInventoryProvider provider = Provider.of(context, listen: false); - Map payload = { "assetNumber": assetNo, "sessionId": widget.assetInventoryModel?.sessionId, @@ -415,11 +401,20 @@ class _AssetInventoryFormViewState extends State { _scannedAssetModel?.departmentId = widget.assetInventoryModel?.department?.id; _scannedAssetModel?.roomId = widget.assetInventoryModel?.room?.id; _scannedAssetModel?.isNotRegistered = isRegistered; - if (attachments.isNotEmpty) { - String? photoName = attachments.first.name; - String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? ''; - _scannedAssetModel?.photo = fileName; + _scannedAssetModel?.assetInventoryDetailAssetAttachments = []; + // try { + for (var item in attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + _scannedAssetModel?.assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments(id: item.id, name: fileName)); } + // // } catch (error) { + // // print(error); + // // } + // if (attachments.isNotEmpty) { + // String? photoName = attachments.first.name; + // String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? ''; + // _scannedAssetModel?.photo = fileName; + // } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async { ///Need to use push and remove until... diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart index 88e21b07..b9a3de09 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -86,7 +86,7 @@ class _AssetInventoryPageState extends State { indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)), onTap: (index) {}, tabs: [ - Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight), + Tab(text: 'Session Details'.addTranslation, height: 57.toScreenHeight), Tab( text: '${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}', diff --git a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart index 8d9abfdd..51771032 100644 --- a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart +++ b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart @@ -26,12 +26,6 @@ class InventorySessionItemView extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - StatusLabel( - label: requestData!.priorityName!, - textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!), - backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!), - ), - 8.width, StatusLabel( label: requestData!.statusName!, textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!), @@ -73,12 +67,6 @@ class InventorySessionItemView extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - StatusLabel( - label: requestDetails!.priority!, - textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!), - backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!), - ), - 8.width, StatusLabel( label: requestDetails!.status!, textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!), diff --git a/pubspec.lock b/pubspec.lock index fdc4903d..902236f8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1570,6 +1570,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + tree_view_flutter: + dependency: "direct main" + description: + name: tree_view_flutter + sha256: "3365e29b7d1b1e6c5098a2a0e77a208a12a9345dfa73865cb4c87657cf387801" + url: "https://pub.dev" + source: hosted + version: "1.0.2" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 70641f4d..e7584098 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,6 +95,7 @@ dependencies: safe_device: ^1.2.1 toggle_switch: ^2.3.0 clipboard: ^2.0.2 + tree_view_flutter: ^1.0.2 local_auth_darwin: any dev_dependencies: From 5c8e1d576341c08a31df3238e689c62aecc0eb08 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 11 Nov 2025 08:50:35 +0300 Subject: [PATCH 08/19] bug fixes. --- .../traf_module/create_traf_request_page.dart | 20 +++++++++++-- .../traf_module/traf_request_detail_page.dart | 30 +++++++++++++------ .../traf_module/traf_request_model.dart | 8 +++++ 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart index 05670e01..fd895ee1 100644 --- a/lib/modules/traf_module/create_traf_request_page.dart +++ b/lib/modules/traf_module/create_traf_request_page.dart @@ -310,7 +310,7 @@ class _CreateTRAFRequestPageState extends State { initialValue: isUsedSolelyOrShared, onSelect: (value) { isUsedSolelyOrShared = value; - trafRequest?.usingSolelyOrSharedId = value?.value; + trafRequest?.usingSolelyOrSharedId = value?.id; if (isUsedSolelyOrShared?.value != 1) { departments = []; trafRequest?.trafDepartments = []; @@ -353,7 +353,7 @@ class _CreateTRAFRequestPageState extends State { initialValue: otherServicesEffects, onSelect: (value) { otherServicesEffects = value; - trafRequest?.isEffectedId = value?.value; + trafRequest?.isEffectedId = value?.id; if (otherServicesEffects?.value != 1) { trafRequest?.effectedServices = null; FocusScope.of(context).unfocus(); @@ -395,7 +395,7 @@ class _CreateTRAFRequestPageState extends State { initialValue: useInCombination, onSelect: (value) { useInCombination = value; - trafRequest?.isCombinationId = value?.value; + trafRequest?.isCombinationId = value?.id; if (useInCombination?.value != 1) { trafRequest?.usedWithCombination = null; FocusScope.of(context).unfocus(); @@ -483,11 +483,25 @@ class _CreateTRAFRequestPageState extends State { "Please specify users going to use technology".showToast; return; } + if (isUsedSolelyOrShared == null) { + "Please specify technology solely or shared".showToast; + return; + } if (isUsedSolelyOrShared?.value == 1 && (trafRequest?.trafDepartments ?? []).isEmpty) { "Please specify departments and relations".showToast; return; } + if (otherServicesEffects == null) { + "Please specify other services will be effected or not".showToast; + return; + } + + if (useInCombination == null) { + "Please specify equipment used in combination or not".showToast; + return; + } + Utils.showLoading(context); bool isSuccess = await Provider.of(context, listen: false).addTraf(trafRequest!.toJson()); Utils.hideLoading(context); diff --git a/lib/modules/traf_module/traf_request_detail_page.dart b/lib/modules/traf_module/traf_request_detail_page.dart index c69073c7..3eac9725 100644 --- a/lib/modules/traf_module/traf_request_detail_page.dart +++ b/lib/modules/traf_module/traf_request_detail_page.dart @@ -93,14 +93,14 @@ class _TrafRequestDetailPageState extends State { ), 8.height, '${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context), - '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), // todo ask shaheer - '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), // todo ask shaheer - 'Position: ${data.positionName ?? '-'}'.bodyText(context), // todo ask shaheer + '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), + '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), + 'Position: ${data.positionName ?? '-'}'.bodyText(context), '${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context), - '${context.translation.department}: ${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context), - 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context), - '${context.translation.extensionNo}: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context), - '${context.translation.phoneNumber}: ${data.requesterContactNumber ?? '-'}'.bodyText(context), + '${context.translation.department}: ${data.departmentName}'.bodyText(context), + // 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context), + 'Number/Contact Information: ${data.requesterContactNumber ?? '-'}'.bodyText(context), + 'Extension: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context), ], ).toShadowContainer(context, borderRadius: 20, padding: 12); } @@ -131,10 +131,22 @@ class _TrafRequestDetailPageState extends State { .bodyText(context), 4.height, 'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context), + if ((data.departments ?? []).isNotEmpty) ...[ + 4.height, + 'Technology used with other departments:\n${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context), + ], 4.height, - 'Would other services be effected by acquiring the new equipment?:\n${data.effectedServices ?? '-'}'.bodyText(context), + 'Would other services be effected by acquiring the new equipment?:\n${data.isEffectedName ?? '-'}'.bodyText(context), + if ((data.effectedServices ?? "").isNotEmpty) ...[ + 4.height, + 'List of services would it be effected:\n${data.effectedServices ?? '-'}'.bodyText(context), + ], 4.height, - 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.usedWithCombination ?? '-'}'.bodyText(context), + 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.isCombinationName ?? '-'}'.bodyText(context), + if ((data.usedWithCombination ?? "").isNotEmpty) ...[ + 4.height, + 'Equipment going to be used with combination of other equipments:\n${data.usedWithCombination ?? '-'}'.bodyText(context), + ], ], ).toShadowContainer(context, borderRadius: 20, padding: 12); } diff --git a/lib/modules/traf_module/traf_request_model.dart b/lib/modules/traf_module/traf_request_model.dart index 9234ba60..af3977be 100644 --- a/lib/modules/traf_module/traf_request_model.dart +++ b/lib/modules/traf_module/traf_request_model.dart @@ -51,6 +51,8 @@ class TrafRequestDataModel { String? employeeEmail; int? positionId; String? positionName; + String? departmentId; + String? departmentName; List? departments; List? trafDepartments; int? siteId; @@ -147,6 +149,8 @@ class TrafRequestDataModel { this.employeeEmail, this.positionId, this.positionName, + this.departmentId, + this.departmentName, this.departments, this.trafDepartments, this.siteId, @@ -243,6 +247,8 @@ class TrafRequestDataModel { employeeEmail = json['employeeEmail']; positionId = json['positionId']; positionName = json['positionName']; + departmentId = json['departmentId']; + departmentName = json['departmentName']; if (json['departments'] != null) { departments = []; json['departments'].forEach((v) { @@ -366,6 +372,8 @@ class TrafRequestDataModel { data['employeeEmail'] = this.employeeEmail; data['positionId'] = this.positionId; data['positionName'] = this.positionName; + data['departmentId'] = this.departmentId; + data['departmentName'] = this.departmentName; if (this.departments != null) { data['departments'] = this.departments!.map((v) => v.toJson()).toList(); } From 675c1fa10b8c0dc5ee7048e5cf65f42a5b8353c2 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 11 Nov 2025 09:12:17 +0300 Subject: [PATCH 09/19] for uat --- lib/controllers/api_routes/urls.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index c2f40b8c..2cc5fa8d 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -5,13 +5,13 @@ class URLs { // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url - static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - // static String _baseUrl = "$_host/mobile"; + static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT + // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation From 233dc19030245c6154f4f99343164cf4b5203711 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 11 Nov 2025 10:27:33 +0300 Subject: [PATCH 10/19] users position added. --- .../new_models/users_based_on_search_model.dart | 16 +++++++--------- .../traf_module/create_traf_request_page.dart | 3 ++- .../traf_module/users_auto_complete_field.dart | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/models/new_models/users_based_on_search_model.dart b/lib/models/new_models/users_based_on_search_model.dart index 54480f91..4dea3117 100644 --- a/lib/models/new_models/users_based_on_search_model.dart +++ b/lib/models/new_models/users_based_on_search_model.dart @@ -6,17 +6,11 @@ class UsersBasedOnSearchModel { int? languageId; String? extensionNo; String? phoneNumber; + String? positionName; + String? position; bool? isActive; - UsersBasedOnSearchModel( - {this.userId, - this.userName, - this.email, - this.employeeId, - this.languageId, - this.extensionNo, - this.phoneNumber, - this.isActive}); + UsersBasedOnSearchModel({this.userId, this.userName, this.email, this.employeeId, this.languageId, this.extensionNo, this.phoneNumber, this.positionName, this.position, this.isActive}); UsersBasedOnSearchModel.fromJson(Map json) { userId = json['userId']; @@ -26,6 +20,8 @@ class UsersBasedOnSearchModel { languageId = json['languageId']; extensionNo = json['extensionNo']; phoneNumber = json['phoneNumber']; + positionName = json['positionName']; + position = json['position']; isActive = json['isActive']; } @@ -38,6 +34,8 @@ class UsersBasedOnSearchModel { data['languageId'] = this.languageId; data['extensionNo'] = this.extensionNo; data['phoneNumber'] = this.phoneNumber; + data['positionName'] = this.positionName; + data['position'] = this.position; data['isActive'] = this.isActive; return data; } diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart index fd895ee1..66133805 100644 --- a/lib/modules/traf_module/create_traf_request_page.dart +++ b/lib/modules/traf_module/create_traf_request_page.dart @@ -288,7 +288,8 @@ class _CreateTRAFRequestPageState extends State { dense: true, contentPadding: EdgeInsets.zero, title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"), - subtitle: Text("Email: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"), + subtitle: Text( + "Position: ${userBasedOnSearch[index].position ?? "-"}\nEmail: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"), trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() { userBasedOnSearch.removeAt(index); setState(() {}); diff --git a/lib/modules/traf_module/users_auto_complete_field.dart b/lib/modules/traf_module/users_auto_complete_field.dart index 12060844..f05e77fa 100644 --- a/lib/modules/traf_module/users_auto_complete_field.dart +++ b/lib/modules/traf_module/users_auto_complete_field.dart @@ -87,7 +87,7 @@ class _UsersAutoCompleteFieldState extends State { }); return workOrders; }, - displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? option.userName ?? "" : option.employeeId ?? "", + displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (${option.position ?? "-"})" ?? "" : option.employeeId ?? "", fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { return TextField( controller: _controller, From 12e971749ecaba898f597db7f20600c3724c175b Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Tue, 11 Nov 2025 10:43:04 +0300 Subject: [PATCH 11/19] rename Oracle Code-> Name/Oracle Code --- lib/modules/traf_module/asset_auto_complete_field.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/traf_module/asset_auto_complete_field.dart b/lib/modules/traf_module/asset_auto_complete_field.dart index 0abb378b..e215c4a7 100644 --- a/lib/modules/traf_module/asset_auto_complete_field.dart +++ b/lib/modules/traf_module/asset_auto_complete_field.dart @@ -105,7 +105,7 @@ class _AssetAutoCompleteFieldState extends State { fillColor: AppColor.fieldBgColor(context), errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), - labelText: context.translation.oracleCode, + labelText: "Name/Oracle Code", labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)), suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null, ), From 830700ce79d164d4d568be55bedd492e99d28996 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 12 Nov 2025 08:53:18 +0300 Subject: [PATCH 12/19] grey error fixed on release build. --- lib/new_views/common_widgets/multiple_item_drop_down_menu.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart index d0df92fa..9adf0b97 100644 --- a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart +++ b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart @@ -210,7 +210,7 @@ class _MultipleItemDropDownMenuState Date: Thu, 13 Nov 2025 14:57:44 +0300 Subject: [PATCH 13/19] APK to provided to FM with fixed tracker issues. --- lib/controllers/api_routes/urls.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2cc5fa8d..09ccf264 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -9,9 +9,9 @@ class URLs { // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url - static String _baseUrl = "$_host/mobile"; + // static String _baseUrl = "$_host/mobile"; // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - // static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT + static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT // static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation From a04ae0c8331b8b5ff4da593cb37932706d2d8f93 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 16 Nov 2025 10:02:58 +0300 Subject: [PATCH 14/19] attachment fixes --- assets/images/attachment_icon.svg | 3 + lib/controllers/api_routes/urls.dart | 1 + lib/main.dart | 4 +- .../activity_maintenance_model.dart | 2 +- .../models/engineer_data_model.dart | 53 +++ .../equipment_internal_audit_data_model.dart | 14 +- .../internal_audit_attachment_model.dart | 14 +- .../system_internal_audit_data_model.dart | 16 + .../system_internal_audit_form_model.dart | 13 +- ...odel.dart => update_audit_form_model.dart} | 37 ++- .../create_equipment_internal_audit_form.dart | 2 +- .../equipment_internal_audit_detail_page.dart | 47 ++- .../update_equipment_internal_audit_page.dart | 257 +++++++-------- .../create_system_internal_audit_form.dart | 25 +- .../system_internal_audit_detail_page.dart | 102 ++++-- .../update_system_internal_audit_page.dart | 301 +++++++++--------- .../provider/internal_audit_provider.dart | 48 ++- 17 files changed, 556 insertions(+), 383 deletions(-) create mode 100644 assets/images/attachment_icon.svg create mode 100644 lib/modules/internal_audit_module/models/engineer_data_model.dart rename lib/modules/internal_audit_module/models/{audit_form_model.dart => update_audit_form_model.dart} (64%) diff --git a/assets/images/attachment_icon.svg b/assets/images/attachment_icon.svg new file mode 100644 index 00000000..d0da9eaf --- /dev/null +++ b/assets/images/attachment_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 36d8e431..e7cf01b2 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -322,6 +322,7 @@ class URLs { static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer"; static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; } diff --git a/lib/main.dart b/lib/main.dart index c5b39ef2..1ad94683 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,6 +31,7 @@ import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart'; @@ -365,7 +366,8 @@ class MyApp extends StatelessWidget { HelpCenterPage.id: (_) => const HelpCenterPage(), CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(), CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(), - UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), + UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(), + UpdateSystemInternalAuditPage.id: (_) => UpdateSystemInternalAuditPage(), // SwipeSuccessView.routeName: (_) => const SwipeSuccessView(), // SwipeHistoryView.routeName: (_) => const SwipeHistoryView(), }, diff --git a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart index dda5432b..21541769 100644 --- a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart +++ b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart @@ -31,11 +31,11 @@ class ActivityMaintenanceHelperModel { WorkOrderAssignedEmployee? assignedEmployee; SuppEngineerWorkOrders? supEngineer; ActivityMaintenanceAssistantEmployees? modelAssistantEmployees; + List? assistantEmployList=[]; List? assistantEmployees; List? activityMaintenanceTimers = []; TimerModel? activityMaintenanceTimerModel = TimerModel(); TimerModel? activityTimePicker; - List? assistantEmployList=[]; List? timerModelList = []; ActivityMaintenanceHelperModel( diff --git a/lib/modules/internal_audit_module/models/engineer_data_model.dart b/lib/modules/internal_audit_module/models/engineer_data_model.dart new file mode 100644 index 00000000..dbb34d24 --- /dev/null +++ b/lib/modules/internal_audit_module/models/engineer_data_model.dart @@ -0,0 +1,53 @@ +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; + +class EngineerData { + int? id; + String? debrief; + String? startTime; + String? endTime; + double? totalHours; + bool? isComplete; + int? statusId; + int? requestId; + List? attachments; + + EngineerData({ + this.id, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.isComplete, + this.statusId, + this.requestId, + this.attachments, + }); + + EngineerData.fromJson(Map json) { + id = json['id']; + debrief = json['debrief']; + startTime = json['startTime']; + endTime = json['endTime']; + totalHours = (json['totalHours'] as num?)?.toDouble(); + isComplete = json['isComplete']; + statusId = json['statusId']; + requestId = json['requestId']; + attachments = json['attachments'] != null ? (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList() : []; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['debrief'] = debrief; + data['startTime'] = startTime; + data['endTime'] = endTime; + data['totalHours'] = totalHours; + data['isComplete'] = isComplete; + data['statusId'] = statusId; + data['requestId'] = requestId; + if (attachments != null) { + data['attachments'] = attachments!.map((e) => e.toJson()).toList(); + } + return data; + } +} \ No newline at end of file diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart index be9c00bb..92f41bab 100644 --- a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart @@ -1,4 +1,5 @@ import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; @@ -15,6 +16,8 @@ class EquipmentInternalAuditDataModel { String? remarks; List? equipmentsFindings; List? attachments; + EngineerData? engineerData; + EquipmentInternalAuditDataModel({ this.id, @@ -29,6 +32,7 @@ class EquipmentInternalAuditDataModel { this.remarks, this.equipmentsFindings, this.attachments, + this.engineerData, }); EquipmentInternalAuditDataModel.fromJson(Map json) { @@ -48,7 +52,14 @@ class EquipmentInternalAuditDataModel { equipmentsFindings!.add(EquipmentsFinding.fromJson(v)); }); } - // attachments = json['attachments'] != null ? List.from(json['attachments']) : []; + attachments = json['attachments'] != null + ? (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .where((e) => e.name != null) // optional filter if you want to skip null names + .toList() + : []; + engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null; + } Map toJson() { @@ -76,6 +87,7 @@ class EquipmentInternalAuditDataModel { equipmentsFindings!.map((v) => v.toJson()).toList(); } data['attachments'] = attachments; + if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } } diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart index a81f2d17..5e21d5ae 100644 --- a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart +++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart @@ -1,23 +1,27 @@ +import 'dart:developer'; + class InternalAuditAttachments { - InternalAuditAttachments({this.id,this.originalName, this.name,this.createdBy}); + InternalAuditAttachments({this.id, this.originalName, this.name, this.createdBy}); int? id; String? name; String? originalName; - String ?createdBy; + String? createdBy; + InternalAuditAttachments.fromJson(Map json) { + log('name is ${json['name']}'); id = json['id']; - name = json['name']; + name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null; originalName = json['originalName']; createdBy = json['createdBy']; } Map toJson() { final Map data = {}; - // data['id'] = id; + data['id'] = id; data['name'] = name; data['originalName'] = originalName; // data['createdBy'] = createdBy; return data; } -} \ No newline at end of file +} diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart index ae84e97f..0546ccdc 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart @@ -1,4 +1,6 @@ import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; class SystemInternalAuditDataModel { @@ -17,6 +19,8 @@ class SystemInternalAuditDataModel { String? createdDate; String? modifiedBy; String? modifiedDate; + List? attachments; + EngineerData? engineerData; SystemInternalAuditDataModel({ this.id, @@ -34,6 +38,8 @@ class SystemInternalAuditDataModel { this.createdDate, this.modifiedBy, this.modifiedDate, + this.attachments, + this.engineerData, }); SystemInternalAuditDataModel.fromJson(Map json) { @@ -52,6 +58,13 @@ class SystemInternalAuditDataModel { createdDate = json['createdDate']; modifiedBy = json['modifiedBy']; modifiedDate = json['modifiedDate']; + attachments = json['attachments'] != null + ? (json['attachments'] as List) + .map((e) => InternalAuditAttachments.fromJson(e)) + .where((e) => e.name != null) // optional filter if you want to skip null names + .toList() + : []; + engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null; } Map toJson() { @@ -71,6 +84,7 @@ class SystemInternalAuditDataModel { data['createdDate'] = createdDate; data['modifiedBy'] = modifiedBy; data['modifiedDate'] = modifiedDate; + if (engineerData != null) data['engineerData'] = engineerData!.toJson(); return data; } } @@ -120,3 +134,5 @@ class Auditor { return data; } } + + diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart index 4082eb03..3fda34d0 100644 --- a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart @@ -1,7 +1,7 @@ - import 'dart:developer'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; class SystemInternalAuditFormModel { int? id; @@ -13,12 +13,13 @@ class SystemInternalAuditFormModel { int? correctiveMaintenanceId; int? planPreventiveVisitId; int? assetTransferId; + List? attachments = []; int? taskJobId; int? taskAlertJobId; int? gasRefillId; int? planRecurrentTaskId; int? statusId; - SystemAuditWorkOrderDetailModel ?workOrderDetailModel; + SystemAuditWorkOrderDetailModel? workOrderDetailModel; SystemInternalAuditFormModel({ this.id, @@ -36,6 +37,7 @@ class SystemInternalAuditFormModel { this.planRecurrentTaskId, this.workOrderDetailModel, this.statusId, + this.attachments, }); Map toJson() { @@ -54,6 +56,7 @@ class SystemInternalAuditFormModel { 'gasRefillId': gasRefillId, 'planRecurrentTaskId': planRecurrentTaskId, 'statusId': statusId, + 'attachments': attachments?.map((e) => e.toJson()).toList(), }; } } @@ -73,12 +76,13 @@ class WoAutoCompleteModel { Map toJson() { final Map data = {}; - data['id'] =id; + data['id'] = id; data['woOrderNo'] = workOrderNo; data['displayName'] = workOrderNo; return data; } } + class SystemAuditWorkOrderDetailModel { String? createdBy; DateTime? createdDate; @@ -196,6 +200,3 @@ class SystemAuditWorkOrderDetailModel { }; } } - - - diff --git a/lib/modules/internal_audit_module/models/audit_form_model.dart b/lib/modules/internal_audit_module/models/update_audit_form_model.dart similarity index 64% rename from lib/modules/internal_audit_module/models/audit_form_model.dart rename to lib/modules/internal_audit_module/models/update_audit_form_model.dart index dd3e6975..6942d51f 100644 --- a/lib/modules/internal_audit_module/models/audit_form_model.dart +++ b/lib/modules/internal_audit_module/models/update_audit_form_model.dart @@ -1,5 +1,6 @@ import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; class AuditFormModel { int? id; @@ -12,19 +13,24 @@ class AuditFormModel { List? attachments; bool? isComplete; TimerModel? auditTimerModel = TimerModel(); + List? auditTimers = []; + TimerModel? auditTimePicker; + List? timerModelList = []; - AuditFormModel({ - this.id, - this.requestId, - this.debrief, - this.startTime, - this.endTime, - this.totalHours, - this.createdDate, - this.attachments, - this.isComplete, - this.auditTimerModel, - }); + AuditFormModel( + {this.id, + this.requestId, + this.debrief, + this.startTime, + this.endTime, + this.totalHours, + this.createdDate, + this.attachments, + this.isComplete, + this.auditTimerModel, + this.timerModelList, + this.auditTimePicker, + this.auditTimers}); AuditFormModel.fromJson(Map json) { id = json['id']; @@ -34,9 +40,7 @@ class AuditFormModel { endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null; totalHours = json['totalHours']?.toDouble(); if (json['attachments'] != null) { - attachments = (json['attachments'] as List) - .map((e) => InternalAuditAttachments.fromJson(e)) - .toList(); + attachments = (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList(); } isComplete = json['isComplete']; } @@ -48,9 +52,10 @@ class AuditFormModel { 'debrief': debrief, 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), + // 'auditTimer': auditTimers, 'totalHours': totalHours, 'attachments': attachments?.map((e) => e.toJson()).toList(), 'isComplete': isComplete, }; } -} \ No newline at end of file +} diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart index db29aee6..532a5b14 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart @@ -111,7 +111,7 @@ class _CreateEquipmentInternalAuditFormState extends State allAttachments = []; @override void initState() { @@ -46,6 +50,13 @@ class _EquipmentInternalAuditDetailPageState extends State getAuditData() async { model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId); + allAttachments.clear(); + allAttachments = [ + ...(model?.attachments ?? []), + ...(model?.engineerData?.attachments ?? []), + ]; + + } @override @@ -62,8 +73,8 @@ class _EquipmentInternalAuditDetailPageState extends State provider.isLoading, builder: (_, isLoading, __) { if (isLoading) return const ALoading(); - if (model==null) return NoDataFound(message: context.translation.noDataFound).center; - return Column( + if (model == null) return NoDataFound(message: context.translation.noDataFound).center; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( @@ -76,24 +87,19 @@ class _EquipmentInternalAuditDetailPageState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), ], - //TODO need to check for attachments backend need to fix the name they are sending wrong string - // if (model!.attachments!.isNotEmpty) ...[ - // const Divider().defaultStyle(context), - // Text( - // "Attachments".addTranslation, - // style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - // ), - // 8.height, - // FilesList(images: model!.attachments!.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), - // ], ], ).paddingAll(0).toShadowContainer(context), ).expanded, @@ -103,8 +109,17 @@ class _EquipmentInternalAuditDetailPageState extends State UpdateEquipmentInternalAuditPage(model: model))); + onPressed: () async { + final result = await Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => UpdateEquipmentInternalAuditPage(model: model), + ), + ); + if (result == true) { + await getAuditData(); + setState(() {}); // refresh UI with new model + } + // Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateEquipmentInternalAuditPage(model: model))); }), ), ], diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart index 02115d62..e5d3072f 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -2,9 +2,9 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; @@ -14,12 +14,14 @@ import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; -import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/working_time_tile.dart'; @@ -32,7 +34,7 @@ class UpdateEquipmentInternalAuditPage extends StatefulWidget { static const String id = "update-equipment-internal-audit"; EquipmentInternalAuditDataModel? model; - UpdateEquipmentInternalAuditPage({Key? key,this.model}) : super(key: key); + UpdateEquipmentInternalAuditPage({Key? key, this.model}) : super(key: key); @override State createState() => _UpdateEquipmentInternalAuditPageState(); @@ -46,6 +48,7 @@ class _UpdateEquipmentInternalAuditPageState extends State _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); List _attachments = []; + //TODO need to check if it's needed or not.. List timerList = []; @@ -54,137 +57,93 @@ class _UpdateEquipmentInternalAuditPageState extends State GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? []; + _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; - } - void calculateWorkingTime() { - // final timers = _formModel.gasRefillTimers ?? []; - // totalWorkingHours = timers.fold(0.0, (sum, item) { - // if (item.startDate == null || item.endDate == null) return sum; - // try { - // final start = DateTime.parse(item.startDate!); - // final end = DateTime.parse(item.endDate!); - // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours - // return sum + diffInHours; - // } catch (_) { - // return sum; - // } - // }); - // - // timerList = timers.map((e) { - // return TimerHistoryModel( - // id: e.id, - // startTime: e.startDate, - // endTime: e.endDate, - // workingHours: e.workingHours, - // ); - // }).toList(); + calculateWorkingTime(); } + void calculateWorkingTime() { + final helperModel = formModel; + final timers = helperModel.auditTimers ?? []; + totalWorkingHours = timers.fold(0.0, (sum, item) { + if (item.startDate == null || item.endDate == null) return sum; + try { + final start = DateTime.parse(item.startDate!); + final end = DateTime.parse(item.endDate!); + final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + return sum + diffInHours; + } catch (_) { + return sum; + } + }); + timerList = timers.map((e) { + return TimerHistoryModel( + id: e.id, + startTime: e.startDate, + endTime: e.endDate, + workingHours: e.startDate, + ); + }).toList(); + } _onSubmit(BuildContext context) async { bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; - InternalAuditProvider provider = Provider.of(context,listen: false); + InternalAuditProvider provider = Provider.of(context, listen: false); + + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + formModel.auditTimers ??= []; + if (formModel.auditTimePicker != null) { + int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null + endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + } + formModel.timerModelList?.forEach((timer) { + int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: timer.startAt!.toIso8601String(), // Handle potential null + endDate: timer.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + }); _formKey.currentState!.save(); formModel.attachments = []; for (var item in _attachments) { - String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') - ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") - : item.name ?? ''; + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; formModel.attachments!.add( InternalAuditAttachments( id: item.id, originalName: fileName, - // name: fileName, + name: fileName, ), ); } - provider.updateEquipmentInternalAudit(model: formModel); + final success = await provider.updateEquipmentInternalAudit(model: formModel); + Navigator.pop(context); + if (formModel.isComplete == true) { + //Navigate to List screen. + } else if (formModel.isComplete == false) { + //Navigate to Detail screen. + if (success) { + Navigator.of(context).pop(true); + } else { + Fluttertoast.showToast(msg: 'Failed to update'); + } - log('payload ${formModel.toJson()}'); - - - - // if (isTimerPickerEnable) { - // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.gasRefillTimePicker == null) { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // } else { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // - // if (_currentDetails.deliverdQty == null) { - // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); - // return false; - // } - // _formModel.gasRefillDetails = []; - // _formModel.gasRefillDetails?.add(_currentDetails); - // - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; - // if (_formModel.gasRefillTimePicker != null) { - // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null - // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // } - // _formModel.timerModelList?.forEach((timer) { - // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: timer.startAt!.toIso8601String(), // Handle potential null - // endDate: timer.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // }); - // _formModel.gasRefillAttachments = []; - // for (var item in _attachments) { - // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; - // _formModel.gasRefillAttachments?.add(GasRefillAttachments( - // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); - // } - - // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { - // Navigator.pop(context); - // if (success) { - // if (status == 1) { - // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - // // when click complete then this request remove from the list and status changes to closed.. - // _gasRefillProvider?.reset(); - // allRequestsProvider.getAllRequests(context, typeTransaction: 2); - // } - // Navigator.pop(context); - // } - // }); + } } @override @@ -206,7 +165,6 @@ class _UpdateEquipmentInternalAuditPageState extends State? timerModelList = []; return Column( mainAxisSize: MainAxisSize.min, children: [ + //TODO multiple timer .. + // AppTimer( + // label: context.translation.timer, + // timer: formModel.auditTimerModel, + // // enabled: enableTimer, + // pickerTimer: formModel.auditTimePicker, + // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + // onPick: (time) { + // formModel.auditTimePicker = time; + // setState(() {}); + // log('Time picker start ${formModel.auditTimePicker?.startAt}'); + // log('Time picker end ${formModel.auditTimePicker?.endAt}'); + // }, + // timerProgress: (isRunning) {}, + // onChange: (timer) async { + // formModel.auditTimerModel = timer; + // log('start ${formModel.auditTimerModel?.startAt}'); + // log('end ${formModel.auditTimerModel?.endAt}'); + // if (timer.startAt != null && timer.endAt != null) { + // formModel.timerModelList = formModel.timerModelList ?? []; + // formModel.timerModelList!.add(timer); + // } + // setState(() {}); + // log('list length ${formModel.timerModelList?.length}'); + // return true; + // }, + // ), AppTimer( label: context.translation.workingHours, - timer: timer, + timer: formModel.auditTimerModel, pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), - pickerTimer: timerPicker, - onPick: (time) { - updateTimer(timer: timer); - + pickerTimer: formModel.auditTimePicker, + onPick: (timer) { + updateTimer(timer: timer); }, width: double.infinity, decoration: BoxDecoration( diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart index a443588d..20ab2451 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart @@ -15,6 +15,7 @@ import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart'; @@ -47,7 +48,7 @@ class _CreateSystemInternalAuditFormState extends State _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - final List _deviceImages = []; + final List _attachments = []; late TextEditingController _woAutoCompleteController; bool showLoading = false; @@ -148,15 +149,14 @@ class _CreateSystemInternalAuditFormState extends State(context, listen: false); if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); + _model.attachments=[]; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + _model.attachments?.add(InternalAuditAttachments(id: item.id, name: fileName)); + } showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); _model.auditorId = context.userProvider.user?.userID; bool status = await internalAuditProvider.addSystemInternalAudit(context: context, request: _model); diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart index 7052f2fd..484d5b4e 100644 --- a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart +++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart @@ -1,19 +1,24 @@ -import 'dart:io'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart'; +import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart'; import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; + import 'package:test_sa/views/widgets/loaders/app_loading.dart'; class SystemInternalAuditDetailPage extends StatefulWidget { @@ -30,8 +35,9 @@ class SystemInternalAuditDetailPage extends StatefulWidget { class _SystemInternalAuditDetailPageState extends State { bool isWoType = true; - // EquipmentInternalAuditDataModel? model; + SystemInternalAuditDataModel? model; late InternalAuditProvider _internalAuditProvider; + List allAttachments = []; @override void initState() { @@ -43,7 +49,12 @@ class _SystemInternalAuditDetailPageState extends State getAuditData() async { - await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); + model = await _internalAuditProvider.getInternalSystemAuditById(widget.auditId); + allAttachments.clear(); + allAttachments = [ + ...(model?.attachments ?? []), + ...(model?.engineerData?.attachments ?? []), + ]; } @override @@ -70,28 +81,27 @@ class _SystemInternalAuditDetailPageState extends State URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), - // ], + if (allAttachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), + Text( + "Attachments".addTranslation, + style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + ), + 8.height, + FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []), + ], ], ).paddingAll(0).toShadowContainer(context), ).expanded, @@ -101,8 +111,16 @@ class _SystemInternalAuditDetailPageState extends State UpdateSystemInternalAuditPage(model: model), + ), + ); + if (result == true) { + await getAuditData(); + setState(() {}); // refresh UI with new model + } }), ), ], @@ -112,6 +130,7 @@ class _SystemInternalAuditDetailPageState extends State createState() => _UpdateInternalAuditPageState(); + State createState() => _UpdateSystemInternalAuditPageState(); } -class _UpdateInternalAuditPageState extends State { +class _UpdateSystemInternalAuditPageState extends State { final bool _isLoading = false; double totalWorkingHours = 0.0; - late UserProvider _userProvider; - final TextEditingController _commentController = TextEditingController(); + AuditFormModel formModel = AuditFormModel(); final TextEditingController _workingHoursController = TextEditingController(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _scaffoldKey = GlobalKey(); - bool _firstTime = true; List _attachments = []; + + //TODO need to check if it's needed or not.. List timerList = []; @override void initState() { + populateForm(); super.initState(); } - void calculateWorkingTime() { - // final timers = _formModel.gasRefillTimers ?? []; - // totalWorkingHours = timers.fold(0.0, (sum, item) { - // if (item.startDate == null || item.endDate == null) return sum; - // try { - // final start = DateTime.parse(item.startDate!); - // final end = DateTime.parse(item.endDate!); - // final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours - // return sum + diffInHours; - // } catch (_) { - // return sum; - // } - // }); - // - // timerList = timers.map((e) { - // return TimerHistoryModel( - // id: e.id, - // startTime: e.startDate, - // endTime: e.endDate, - // workingHours: e.workingHours, - // ); - // }).toList(); + void populateForm() { + formModel.requestId = widget.model?.id; + formModel.id = widget.model?.id; + _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? []; + + calculateWorkingTime(); } - @override - void setState(VoidCallback fn) { - if (mounted) super.setState(() {}); + void calculateWorkingTime() { + final helperModel = formModel; + final timers = helperModel.auditTimers ?? []; + totalWorkingHours = timers.fold(0.0, (sum, item) { + if (item.startDate == null || item.endDate == null) return sum; + try { + final start = DateTime.parse(item.startDate!); + final end = DateTime.parse(item.endDate!); + final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours + return sum + diffInHours; + } catch (_) { + return sum; + } + }); + timerList = timers.map((e) { + return TimerHistoryModel( + id: e.id, + startTime: e.startDate, + endTime: e.endDate, + workingHours: e.startDate, + ); + }).toList(); } - _onSubmit(BuildContext context, int status) async { + _onSubmit(BuildContext context) async { bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + InternalAuditProvider provider = Provider.of(context, listen: false); + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // if (isTimerPickerEnable) { - // if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.gasRefillTimePicker == null) { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // } else { - // if (_formModel.timer?.startAt == null) { - // Fluttertoast.showToast(msg: "Working Hours Required"); - // return false; - // } - // if (_formModel.timer?.endAt == null) { - // Fluttertoast.showToast(msg: "Please Stop The Timer"); - // return false; - // } - // } - // - // if (_currentDetails.deliverdQty == null) { - // await Fluttertoast.showToast(msg: "Delivered Quantity is Required"); - // return false; - // } - // _formModel.gasRefillDetails = []; - // _formModel.gasRefillDetails?.add(_currentDetails); - // - // showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - // _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? []; - // if (_formModel.gasRefillTimePicker != null) { - // int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null - // endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // } - // _formModel.timerModelList?.forEach((timer) { - // int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; - // _formModel.gasRefillTimers?.add( - // GasRefillTimer( - // id: 0, - // startDate: timer.startAt!.toIso8601String(), // Handle potential null - // endDate: timer.endAt?.toIso8601String(), // Handle potential null - // workingHours: ((durationInSecond) / 60 / 60), - // ), - // ); - // }); - // _formModel.gasRefillAttachments = []; - // for (var item in _attachments) { - // String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??''; - // _formModel.gasRefillAttachments?.add(GasRefillAttachments( - // id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName)); - // } + formModel.auditTimers ??= []; + if (formModel.auditTimePicker != null) { + int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null + endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + } + formModel.timerModelList?.forEach((timer) { + int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds; + formModel.auditTimers?.add( + InternalAuditTimerModel( + id: 0, + startDate: timer.startAt!.toIso8601String(), // Handle potential null + endDate: timer.endAt?.toIso8601String(), // Handle potential null + totalWorkingHour: ((durationInSecond) / 60 / 60), + ), + ); + }); - // await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) { - // Navigator.pop(context); - // if (success) { - // if (status == 1) { - // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false); - // // when click complete then this request remove from the list and status changes to closed.. - // _gasRefillProvider?.reset(); - // allRequestsProvider.getAllRequests(context, typeTransaction: 2); - // } - // Navigator.pop(context); - // } - // }); + _formKey.currentState!.save(); + formModel.attachments = []; + for (var item in _attachments) { + String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + formModel.attachments!.add( + InternalAuditAttachments( + id: item.id, + // originalName: fileName, + name: fileName, + ), + ); + } + log('submit press'); + log('data ${formModel.toJson()}'); + final success = await provider.updateSystemInternalAudit(model: formModel); + Navigator.pop(context); + if (formModel.isComplete == true) { + //Navigate to List screen. + } else if (formModel.isComplete == false) { + if (success) { + Navigator.of(context).pop(true); + } else { + Fluttertoast.showToast(msg: 'Failed to update'); + } + } } @override void dispose() { - _commentController.dispose(); _workingHoursController.dispose(); super.dispose(); } void updateTimer({TimerModel? timer}) { - // _formModel.timer = timer; - // if (timer?.startAt != null && timer?.endAt != null) { - // _formModel.timerModelList = _formModel.timerModelList ?? []; - // _formModel.timerModelList!.add(timer!); - // } - // notifyListeners(); + if (timer?.startAt != null && timer?.endAt != null) { + final start = timer!.startAt!; + final end = timer.endAt!; + + final difference = end.difference(start); + final totalHours = difference.inSeconds / 3600.0; + formModel.startTime = start; + formModel.endTime = end; + formModel.totalHours = totalHours; + } } @override Widget build(BuildContext context) { - _userProvider = Provider.of(context); return Scaffold( appBar: DefaultAppBar( title: 'Update Information'.addTranslation, onWillPopScope: () { - _onSubmit(context, 0); + formModel.isComplete = false; + _onSubmit(context); }, ), key: _scaffoldKey, @@ -210,21 +198,22 @@ class _UpdateInternalAuditPageState extends State { hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10), alignLabelWithHint: true, + initialValue: formModel.debrief, backgroundColor: AppColor.fieldBgColor(context), showShadow: false, - controller: _commentController, - onChange: (value) {}, - onSaved: (value) {}, + onSaved: (value) { + formModel.debrief = value; + }, ), 8.height, _timerWidget(context, totalWorkingHours), 16.height, AttachmentPicker( - label: context.translation.attachFiles, + label: 'Upload Attachment', attachment: _attachments, buttonColor: AppColor.primary10, onlyImages: false, - buttonIcon: 'image-plus'.toSvgAsset( + buttonIcon: 'attachment_icon'.toSvgAsset( color: AppColor.primary10, ), ), @@ -238,17 +227,22 @@ class _UpdateInternalAuditPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ AppFilledButton( - label: context.translation.save, - buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, - textColor: context.isDark ? AppColor.white10 : AppColor.black10, - onPressed: () => _onSubmit(context, 0), - ).expanded, + label: context.translation.save, + buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60, + textColor: context.isDark ? AppColor.white10 : AppColor.black10, + onPressed: () { + log('button press '); + formModel.isComplete = false; + _onSubmit(context); + }).expanded, 12.width, AppFilledButton( - label: context.translation.complete, - buttonColor: AppColor.primary10, - onPressed: () => _onSubmit(context, 1), - ).expanded, + label: context.translation.complete, + buttonColor: AppColor.primary10, + onPressed: () { + formModel.isComplete = true; + _onSubmit(context); + }).expanded, ], ), ), @@ -258,35 +252,52 @@ class _UpdateInternalAuditPageState extends State { ).handlePopScope( cxt: context, onSave: () { - _onSubmit(context, 0); + formModel.isComplete = false; + _onSubmit(context); }); } Widget _timerWidget(BuildContext context, double totalWorkingHours) { - TimerModel? timer = TimerModel(); - TimerModel? timerPicker; - List? timerModelList = []; return Column( mainAxisSize: MainAxisSize.min, children: [ + // AppTimer( + // label: context.translation.timer, + // timer: formModel.auditTimerModel, + // // enabled: enableTimer, + // pickerTimer: formModel.auditTimePicker, + // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + // onPick: (time) { + // formModel.auditTimePicker = time; + // }, + // timerProgress: (isRunning) {}, + // onChange: (timer) async { + // formModel.auditTimerModel = timer; + // if (timer.startAt != null && timer.endAt != null) { + // formModel.timerModelList = formModel.timerModelList ?? []; + // formModel.timerModelList!.add(timer); + // } + // return true; + // }, + // ), AppTimer( label: context.translation.workingHours, - timer: timer, - // pickerFromDate: DateTime.tryParse(widget.gasRefillModel?.createdDate ?? ''), - pickerFromDate: DateTime.tryParse(''), - pickerTimer: timerPicker, + timer: formModel.auditTimerModel, + pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''), + pickerTimer: formModel.auditTimePicker, onPick: (time) { - //timerPicker = time; + updateTimer(timer: time); }, width: double.infinity, decoration: BoxDecoration( color: AppColor.fieldBgColor(context), - // color: AppColor.neutral100, borderRadius: BorderRadius.circular(10), ), timerProgress: (isRunning) {}, onChange: (timer) async { updateTimer(timer: timer); + log('here onChange ${timer.startAt}'); + return true; }, ), diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart index 314fb2d9..75f0a436 100644 --- a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart +++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart @@ -10,9 +10,10 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/models/device/asset_search.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart'; -import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart'; +import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart'; import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; @@ -57,22 +58,30 @@ class InternalAuditProvider extends ChangeNotifier { } } - Future getInternalSystemAuditById(int id) async { + Future getInternalSystemAuditById(int id) async { try { isLoading = true; notifyListeners(); Response response = await ApiManager.instance.get("${URLs.getInternalAuditSystemById}?AuditSystemId=$id"); - if (response.statusCode >= 200 && response.statusCode < 300) {} - isLoading = false; - notifyListeners(); - return 0; + if (response.statusCode >= 200 && response.statusCode < 300) { + final decodedBody = jsonDecode(response.body); + SystemInternalAuditDataModel model = SystemInternalAuditDataModel.fromJson(decodedBody["data"]); + isLoading = false; + notifyListeners(); + return model; + } else { + isLoading = false; + notifyListeners(); + return null; + } } catch (error) { isLoading = false; notifyListeners(); - return -1; + return null; } } - Future loadAllWorkOrderDetailsByID({required int workOrderTypeId,required int workOrderId}) async { + + Future loadAllWorkOrderDetailsByID({required int workOrderTypeId, required int workOrderId}) async { try { isLoading = true; notifyListeners(); @@ -94,6 +103,7 @@ class InternalAuditProvider extends ChangeNotifier { return null; } } + Future updateEquipmentInternalAudit({required AuditFormModel model}) async { isLoading = true; Response response; @@ -114,6 +124,27 @@ class InternalAuditProvider extends ChangeNotifier { } } + Future updateSystemInternalAudit({required AuditFormModel model}) async { + isLoading = true; + Response response; + try { + response = await ApiManager.instance.put(URLs.updateAuditSystemEngineer, body: model.toJson()); + stateCode = response.statusCode; + isLoading = false; + notifyListeners(); + log('status code ${stateCode}'); + if (stateCode == 200) { + return true; + } + return false; + } catch (error) { + isLoading = false; + stateCode = -1; + notifyListeners(); + return false; + } + } + Future addEquipmentInternalAudit({ required BuildContext context, required EquipmentInternalAuditFormModel request, @@ -137,6 +168,7 @@ class InternalAuditProvider extends ChangeNotifier { return status; } } + Future addSystemInternalAudit({ required BuildContext context, required SystemInternalAuditFormModel request, From 659f2029dcddf377d7a9244932bf810d14e23971 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Sun, 16 Nov 2025 11:19:10 +0300 Subject: [PATCH 15/19] label changes --- .../asset_inventory_module/pages/asset_detail_card_view.dart | 3 +++ .../asset_inventory_module/pages/asset_inventory_page.dart | 2 +- .../pages/inventory_session_item_view.dart | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart index 2bb74028..9d128718 100644 --- a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart +++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart @@ -45,6 +45,9 @@ class AssetDetailCardView extends StatelessWidget { Text( '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), + ), Text( + '${context.translation.assetName}: ${assetInventoryModel.assetName ?? '-'}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), ), Text( '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart index b9a3de09..6240373c 100644 --- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart +++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart @@ -58,7 +58,7 @@ class _AssetInventoryPageState extends State { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: DefaultAppBar( - title: 'Inventory Session Request'.addTranslation, + title: 'Asset Inventory Session'.addTranslation, onBackPress: () { Navigator.pop(context); }, diff --git a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart index 51771032..12adb610 100644 --- a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart +++ b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart @@ -41,7 +41,7 @@ class InventorySessionItemView extends StatelessWidget { ), 8.height, (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), - infoWidget(label: context.translation.requestType, value: requestData?.sessionType, context: context), + infoWidget(label: 'Session Type'.addTranslation, value: requestData?.sessionType, context: context), infoWidget(label: 'No of Assets'.addTranslation, value: requestData?.numberOfAssets != null ? requestData?.numberOfAssets.toString() : '-', context: context), infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context), 8.height, @@ -82,7 +82,7 @@ class InventorySessionItemView extends StatelessWidget { ), 8.height, (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), - infoWidget(label: context.translation.requestType, value: requestDetails?.sessionType, context: context), + infoWidget(label: 'Session Type'.addTranslation, value: requestDetails?.sessionType, context: context), infoWidget(label: 'No of Assets'.addTranslation, value: requestDetails?.numberOfAssets != null ? requestDetails?.numberOfAssets.toString() : '-', context: context), infoWidget(label: 'No of Sites'.addTranslation, value: requestDetails?.numberOfSites != null ? requestDetails?.numberOfSites.toString() : '-', context: context), 8.height, From 59d21ae72e4cd03cf5d8df2e13c9be579924a450 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 09:15:26 +0300 Subject: [PATCH 16/19] jira 1430 & 1434 & 1437 fixed. --- lib/controllers/api_routes/urls.dart | 7 +- .../providers/api/oracle_code_provider.dart | 2 +- .../providers/api/search_user_provider.dart | 2 +- .../traf_module/asset_analytics_model.dart | 172 ++++++++++++++++++ .../traf_module/traf_request_detail_page.dart | 34 +++- .../traf_module/traf_request_provider.dart | 13 ++ .../users_auto_complete_field.dart | 2 +- 7 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 lib/modules/traf_module/asset_analytics_model.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 7f8a61e9..9b1ef1e3 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -5,8 +5,8 @@ class URLs { // static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url - static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis @@ -263,7 +263,9 @@ class URLs { //Traf static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // get + static get getAssetAnalytics => "$_baseUrl/Asset/GetAssetAnalytics"; // get static get getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get + static get getAssetNameAutoComplete => "$_baseUrl/AssetNameDefinition/GetAssetNameAutoComplete"; // get// get //gas refill static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get @@ -300,6 +302,7 @@ class URLs { static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get + static get getUserByRoleValueSiteMobileAutocomplete => "$_baseUrl/Account/GetUserByRoleValueSiteMobileAutocomplete"; // get // pentry static get getPentry => "$_baseUrl/return/pentry/details"; // get diff --git a/lib/controllers/providers/api/oracle_code_provider.dart b/lib/controllers/providers/api/oracle_code_provider.dart index ea8b0978..71375675 100644 --- a/lib/controllers/providers/api/oracle_code_provider.dart +++ b/lib/controllers/providers/api/oracle_code_provider.dart @@ -88,7 +88,7 @@ class OracleCodeProvider extends ChangeNotifier { Future> getAssetByOracleCode(String oracleCode) async { late Response response; try { - response = await ApiManager.instance.post(URLs.getAssetNDAutoCompleteByDynamicCodes, body: {"codeValue": oracleCode}); + response = await ApiManager.instance.post(URLs.getAssetNameAutoComplete, body: {"pageSize": 1, "pageNumber": 20, "searchText": oracleCode}); List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received diff --git a/lib/controllers/providers/api/search_user_provider.dart b/lib/controllers/providers/api/search_user_provider.dart index cdaecdb2..e29b1487 100644 --- a/lib/controllers/providers/api/search_user_provider.dart +++ b/lib/controllers/providers/api/search_user_provider.dart @@ -49,7 +49,7 @@ class UserSearchProvider extends ChangeNotifier { Future> getUsersBasedOnSearch(String query) async { late Response response; try { - response = await ApiManager.instance.get(URLs.getUsersBasedOnSearch + "?roleValue=R-7&searchText=$query"); + response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=1&roleValue=R-7&searchText=$query"); List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received diff --git a/lib/modules/traf_module/asset_analytics_model.dart b/lib/modules/traf_module/asset_analytics_model.dart new file mode 100644 index 00000000..2f265c1b --- /dev/null +++ b/lib/modules/traf_module/asset_analytics_model.dart @@ -0,0 +1,172 @@ +class AssetAnalytics { + num? assetId; + String? assetNumber; + String? assetName; + num? lastPrice; + String? lastPONo; + String? lastPODate; + num? sameAssetQuantity; + String? slaStatus; + String? contractNumber; + String? contractStartDate; + String? contractEndDate; + num? assetAgeInDays; + String? assetAgeDescription; + num? totalMaintenanceCost; + num? sparePartCost; + num? laborCost; + num? exchangeCost; + num? travelCost; + num? netBookValue; + num? purchasedPrice; + num? lifeSpan; + num? mtbf; + String? mtbfDescription; + num? totalCMWorkOrders; + num? downTimeHours; + String? downTimeDescription; + num? upTimeHours; + String? upTimeDescription; + num? operationHours; + String? installationDate; + String? modelName; + String? manufacturerName; + String? serialNumber; + String? departmentName; + String? siteName; + num? id; + String? createdBy; + String? createdDate; + String? modifiedBy; + String? modifiedDate; + + AssetAnalytics( + {this.assetId, + this.assetNumber, + this.assetName, + this.lastPrice, + this.lastPONo, + this.lastPODate, + this.sameAssetQuantity, + this.slaStatus, + this.contractNumber, + this.contractStartDate, + this.contractEndDate, + this.assetAgeInDays, + this.assetAgeDescription, + this.totalMaintenanceCost, + this.sparePartCost, + this.laborCost, + this.exchangeCost, + this.travelCost, + this.netBookValue, + this.purchasedPrice, + this.lifeSpan, + this.mtbf, + this.mtbfDescription, + this.totalCMWorkOrders, + this.downTimeHours, + this.downTimeDescription, + this.upTimeHours, + this.upTimeDescription, + this.operationHours, + this.installationDate, + this.modelName, + this.manufacturerName, + this.serialNumber, + this.departmentName, + this.siteName, + this.id, + this.createdBy, + this.createdDate, + this.modifiedBy, + this.modifiedDate}); + + AssetAnalytics.fromJson(Map json) { + assetId = json['assetId']; + assetNumber = json['assetNumber']; + assetName = json['assetName']; + lastPrice = json['lastPrice']; + lastPONo = json['lastPONo']; + lastPODate = json['lastPODate']; + sameAssetQuantity = json['sameAssetQuantity']; + slaStatus = json['slaStatus']; + contractNumber = json['contractNumber']; + contractStartDate = json['contractStartDate']; + contractEndDate = json['contractEndDate']; + assetAgeInDays = json['assetAgeInDays']; + assetAgeDescription = json['assetAgeDescription']; + totalMaintenanceCost = json['totalMaintenanceCost']; + sparePartCost = json['sparePartCost']; + laborCost = json['laborCost']; + exchangeCost = json['exchangeCost']; + travelCost = json['travelCost']; + netBookValue = json['netBookValue']; + purchasedPrice = json['purchasedPrice']; + lifeSpan = json['lifeSpan']; + mtbf = json['mtbf']; + mtbfDescription = json['mtbfDescription']; + totalCMWorkOrders = json['totalCMWorkOrders']; + downTimeHours = json['downTimeHours']; + downTimeDescription = json['downTimeDescription']; + upTimeHours = json['upTimeHours']; + upTimeDescription = json['upTimeDescription']; + operationHours = json['operationHours']; + installationDate = json['installationDate']; + modelName = json['modelName']; + manufacturerName = json['manufacturerName']; + serialNumber = json['serialNumber']; + departmentName = json['departmentName']; + siteName = json['siteName']; + id = json['id']; + createdBy = json['createdBy']; + createdDate = json['createdDate']; + modifiedBy = json['modifiedBy']; + modifiedDate = json['modifiedDate']; + } + + Map toJson() { + final Map data = new Map(); + data['assetId'] = this.assetId; + data['assetNumber'] = this.assetNumber; + data['assetName'] = this.assetName; + data['lastPrice'] = this.lastPrice; + data['lastPONo'] = this.lastPONo; + data['lastPODate'] = this.lastPODate; + data['sameAssetQuantity'] = this.sameAssetQuantity; + data['slaStatus'] = this.slaStatus; + data['contractNumber'] = this.contractNumber; + data['contractStartDate'] = this.contractStartDate; + data['contractEndDate'] = this.contractEndDate; + data['assetAgeInDays'] = this.assetAgeInDays; + data['assetAgeDescription'] = this.assetAgeDescription; + data['totalMaintenanceCost'] = this.totalMaintenanceCost; + data['sparePartCost'] = this.sparePartCost; + data['laborCost'] = this.laborCost; + data['exchangeCost'] = this.exchangeCost; + data['travelCost'] = this.travelCost; + data['netBookValue'] = this.netBookValue; + data['purchasedPrice'] = this.purchasedPrice; + data['lifeSpan'] = this.lifeSpan; + data['mtbf'] = this.mtbf; + data['mtbfDescription'] = this.mtbfDescription; + data['totalCMWorkOrders'] = this.totalCMWorkOrders; + data['downTimeHours'] = this.downTimeHours; + data['downTimeDescription'] = this.downTimeDescription; + data['upTimeHours'] = this.upTimeHours; + data['upTimeDescription'] = this.upTimeDescription; + data['operationHours'] = this.operationHours; + data['installationDate'] = this.installationDate; + data['modelName'] = this.modelName; + data['manufacturerName'] = this.manufacturerName; + data['serialNumber'] = this.serialNumber; + data['departmentName'] = this.departmentName; + data['siteName'] = this.siteName; + data['id'] = this.id; + data['createdBy'] = this.createdBy; + data['createdDate'] = this.createdDate; + data['modifiedBy'] = this.modifiedBy; + data['modifiedDate'] = this.modifiedDate; + return data; + } +} diff --git a/lib/modules/traf_module/traf_request_detail_page.dart b/lib/modules/traf_module/traf_request_detail_page.dart index 3eac9725..00f25512 100644 --- a/lib/modules/traf_module/traf_request_detail_page.dart +++ b/lib/modules/traf_module/traf_request_detail_page.dart @@ -15,6 +15,7 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; +import 'asset_analytics_model.dart'; import 'traf_request_model.dart'; class TrafRequestDetailPage extends StatefulWidget { @@ -165,16 +166,29 @@ class _TrafRequestDetailPageState extends State { '${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context), '${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context), if (data.requestTypeId == 733) ...[ - 'Last price & PO: ${data.poNumber ?? '-'}'.bodyText(context), - 'The quantity of the same asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Existing asset under SLA: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Age of the asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Total Maintenance Cost (TMC): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Net Book Value (NBV): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Mean Time Between Failure (MTBF): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Down Time (DT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Up Time (UT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer - 'Purchased Price: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer + FutureBuilder( + future: Provider.of(context, listen: false).getAssetAnalytics(data.assetId!), + builder: (cxt, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const SizedBox.square(dimension: 24, child: CircularProgressIndicator()).center; + } + if (snapshot.hasData) { + return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + 'Last price: ${snapshot.data?.lastPrice ?? '-'}'.bodyText(context), + 'PO: ${snapshot.data?.lastPONo ?? '-'}'.bodyText(context), + 'The quantity of the same asset: ${snapshot.data?.sameAssetQuantity ?? '-'}'.bodyText(context), // todo check with shaheer + 'Existing asset under SLA: ${snapshot.data?.slaStatus ?? '-'}'.bodyText(context), // todo check with shaheer + 'Age of the asset: ${snapshot.data?.assetAgeDescription ?? '-'}'.bodyText(context), // todo check with shaheer + 'Total Maintenance Cost (TMC): ${snapshot.data?.totalMaintenanceCost ?? '-'}'.bodyText(context), // todo check with shaheer + 'Net Book Value (NBV): ${snapshot.data?.netBookValue ?? '-'}'.bodyText(context), // todo check with shaheer + 'Mean Time Between Failure (MTBF): ${snapshot.data?.mtbfDescription ?? '-'}'.bodyText(context), // todo check with shaheer + 'Down Time (DT): ${snapshot.data?.downTimeDescription ?? '-'}'.bodyText(context), // todo check with shaheer + 'Up Time (UT): ${snapshot.data?.upTimeDescription ?? '-'}'.bodyText(context), + 'Purchased Price: ${snapshot.data?.purchasedPrice ?? '-'}'.bodyText(context), + ]); + } + return const SizedBox(); + }) ], ], ).toShadowContainer(context, borderRadius: 20, padding: 12); diff --git a/lib/modules/traf_module/traf_request_provider.dart b/lib/modules/traf_module/traf_request_provider.dart index 3626eab0..346f7351 100644 --- a/lib/modules/traf_module/traf_request_provider.dart +++ b/lib/modules/traf_module/traf_request_provider.dart @@ -5,6 +5,7 @@ import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'asset_analytics_model.dart'; import 'traf_request_model.dart'; class TrafRequestProvider extends ChangeNotifier { @@ -43,4 +44,16 @@ class TrafRequestProvider extends ChangeNotifier { return -1; } } + + Future getAssetAnalytics(int assetId) async { + try { + Response response = await ApiManager.instance.get("${URLs.getAssetAnalytics}?assetId=$assetId"); + if (response.statusCode >= 200 && response.statusCode < 300) { + return AssetAnalytics.fromJson(json.decode(response.body)["data"]); + } + } catch (error) { + print(error); + } + return null; + } } diff --git a/lib/modules/traf_module/users_auto_complete_field.dart b/lib/modules/traf_module/users_auto_complete_field.dart index f05e77fa..eae48e41 100644 --- a/lib/modules/traf_module/users_auto_complete_field.dart +++ b/lib/modules/traf_module/users_auto_complete_field.dart @@ -87,7 +87,7 @@ class _UsersAutoCompleteFieldState extends State { }); return workOrders; }, - displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (${option.position ?? "-"})" ?? "" : option.employeeId ?? "", + displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (Nurse)" ?? "" : option.employeeId ?? "", fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { return TextField( controller: _controller, From e1c06a185750707dd8dfe84777eb5b7bf60ac0a5 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 09:25:08 +0300 Subject: [PATCH 17/19] site id improvement --- lib/controllers/providers/api/search_user_provider.dart | 4 ++-- lib/modules/traf_module/users_auto_complete_field.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/controllers/providers/api/search_user_provider.dart b/lib/controllers/providers/api/search_user_provider.dart index e29b1487..f13a30ca 100644 --- a/lib/controllers/providers/api/search_user_provider.dart +++ b/lib/controllers/providers/api/search_user_provider.dart @@ -46,10 +46,10 @@ class UserSearchProvider extends ChangeNotifier { notifyListeners(); } - Future> getUsersBasedOnSearch(String query) async { + Future> getUsersBasedOnSearch(int siteId, String query) async { late Response response; try { - response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=1&roleValue=R-7&searchText=$query"); + response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=$siteId&roleValue=R-7&searchText=$query"); List page = []; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received diff --git a/lib/modules/traf_module/users_auto_complete_field.dart b/lib/modules/traf_module/users_auto_complete_field.dart index eae48e41..c5d04db7 100644 --- a/lib/modules/traf_module/users_auto_complete_field.dart +++ b/lib/modules/traf_module/users_auto_complete_field.dart @@ -81,7 +81,7 @@ class _UsersAutoCompleteFieldState extends State { loading = true; }); } - List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text)); + List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(context.userProvider.user!.clientId!, textEditingValue.text)); setState(() { loading = false; }); From 542070c7913f9442530f6e14e788f4056b2e8a8c Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 19 Nov 2025 11:24:04 +0300 Subject: [PATCH 18/19] improvements --- lib/models/user.dart | 6 ++---- .../update_equipment_internal_audit_page.dart | 1 + .../update_system_internal_audit_page.dart | 2 ++ .../land_page/my_request/all_requests_filter_page.dart | 8 +++++--- lib/views/widgets/timer/app_timer.dart | 5 ++++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/models/user.dart b/lib/models/user.dart index 2c4f3e19..de6f88b8 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -98,8 +98,6 @@ class User { UsersTypes? get type { switch (userRoles?.first.value) { - case "R-7": // Head Nurse Role - return UsersTypes.qualityUser; case "R-6": return UsersTypes.engineer; case "R-7": // Nurse Role @@ -110,8 +108,8 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; - //TODO need to replace with actual data when confirm - + case "R-3": // Quality User + return UsersTypes.qualityUser; default: return null; } diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart index e5d3072f..f69e4a10 100644 --- a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart +++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart @@ -292,6 +292,7 @@ class _UpdateEquipmentInternalAuditPageState extends State { if (isEngineer) { types[context.translation.recurrentWo] = 5; - types["Internal Audit".addTranslation] = 10; + types["Equipment Internal Audit".addTranslation] = 10; + types["System Internal Audit".addTranslation] = 11; } if (context.settingProvider.isUserFlowMedical) { @@ -83,8 +84,9 @@ class _AllRequestsFilterPageState extends State { if (context.userProvider.isAssessor) { types = {"TRAF": 9}; - }if (context.userProvider.isQualityUser) { - types = {"Internal Audit": 10}; + } + if (context.userProvider.isQualityUser) { + types = {'Equipment Internal Audit': 10, 'System Internal Audit': 11}; } final statuses = { diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart index 84179d92..629ad60c 100644 --- a/lib/views/widgets/timer/app_timer.dart +++ b/lib/views/widgets/timer/app_timer.dart @@ -22,6 +22,7 @@ class AppTimer extends StatefulWidget { final TextStyle? style; final BoxDecoration? decoration; final bool enabled; + final bool showPicker; final String? label; final double? width; @@ -40,6 +41,7 @@ class AppTimer extends StatefulWidget { this.onPick, this.timerProgress, this.enabled = true, + this.showPicker = true, }) : super(key: key); @override @@ -126,7 +128,8 @@ class _AppTimerState extends State { @override void initState() { - canPickTime = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; + ///this is temp check for internal audit + canPickTime = widget.showPicker == false ? false : ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false; _startAt = widget.timer?.startAt; _endAt = widget.timer?.endAt; _running = _startAt != null && _endAt == null; From 92a94577d50d2d360825f89250025fa841348dfd Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Thu, 20 Nov 2025 11:51:42 +0300 Subject: [PATCH 19/19] merge conflict resolved. --- lib/controllers/api_routes/urls.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 47183ee1..9ff0dce7 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -346,14 +346,24 @@ class URLs { //internal Audit static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; + static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2"; + static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; + static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; + static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; + static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; + static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; + static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; + static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; + static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer"; + static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID"; }