From 3944a549b229149dda8da4cceddf47623f9ad587 Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 14 Jan 2026 09:20:32 +0300 Subject: [PATCH] requested changes done --- lib/controllers/api_routes/urls.dart | 9 +- .../providers/api/all_requests_provider.dart | 6 +- .../providers/api/user_provider.dart | 1 + lib/dashboard_latest/dashboard_provider.dart | 92 ++++-- lib/extensions/enum_extensions.dart | 6 + lib/main.dart | 2 + lib/models/enums/user_types.dart | 3 +- lib/models/user.dart | 3 + .../helper_function.dart | 72 +++++ .../models/cost_center_model.dart | 5 - .../cost_center_serial_no_form_model.dart | 53 +++ .../delivery_inspection_form_model.dart | 30 +- .../models/inspection_person_model.dart | 15 + .../pages/attachment_view.dart | 133 ++++---- .../cost_center_form_view.dart | 305 +++++++++++++----- .../delivery_inspection_form_view.dart | 274 ++++++++++++---- .../inpection_bottomsheet.dart | 152 +++++++++ .../end_user_cost_center_list_view.dart | 8 +- .../technical_inspection_lines_list_view.dart | 14 +- .../provider/asset_delivery_provider.dart | 38 ++- .../provider/attachment_type_provider.dart | 33 ++ .../my_request/all_requests_filter_page.dart | 6 + .../my_request/my_requests_page.dart | 9 +- 23 files changed, 1017 insertions(+), 252 deletions(-) create mode 100644 lib/modules/asset_delivery_module/helper_function.dart create mode 100644 lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart create mode 100644 lib/modules/asset_delivery_module/models/inspection_person_model.dart create mode 100644 lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart create mode 100644 lib/modules/asset_delivery_module/provider/attachment_type_provider.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index bacf721a..2c8c2a6b 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -68,9 +68,11 @@ class URLs { //service request new flow urls. static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount'; static get qaAuditorCount => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorCount'; + static get commissioningEngineerCount => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerCount'; static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails'; static get qaAuditorDetails => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorDetails'; + static get commissioningEngineerDetails => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerDetails'; static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject'; @@ -413,8 +415,10 @@ class URLs { static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo'; static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection'; + static get getCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterAndSerialNoToLineDeliveryInspection'; static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo'; static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection'; + static get saveCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterAndSerialNoToLineDeliveryInspection'; static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories'; //Technical Inscption... static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection'; @@ -425,7 +429,7 @@ class URLs { static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal"; static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal"; static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem"; - static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachments"; + static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachmentsBasedOnType"; static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save"; //End user Acceptance... static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter"; @@ -433,5 +437,6 @@ class URLs { static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster"; static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail"; static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534"; - static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007"; + static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=415"; + static get attachmentTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5009"; } diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart index 5036ea9c..86579328 100644 --- a/lib/controllers/providers/api/all_requests_provider.dart +++ b/lib/controllers/providers/api/all_requests_provider.dart @@ -166,7 +166,11 @@ class AllRequestsProvider extends ChangeNotifier { if (context.userProvider.isNurse) { list.add(9); // } - list.add(12); // loan module + list.add(12); + if (context.userProvider.isCommissioningEngineer) { + list = [13]; + } + // loan module return list; } diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart index ad64c8b8..d82a6b2d 100644 --- a/lib/controllers/providers/api/user_provider.dart +++ b/lib/controllers/providers/api/user_provider.dart @@ -47,6 +47,7 @@ class UserProvider extends ChangeNotifier { bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl; bool get isQualityUser => user!.type == UsersTypes.qualityUser; + bool get isCommissioningEngineer => user!.type == UsersTypes.commissioningEngineer; VerifyOtpModel _verifyOtpModel = VerifyOtpModel(); SwipeTransaction _swipeTransactionModel = SwipeTransaction(); diff --git a/lib/dashboard_latest/dashboard_provider.dart b/lib/dashboard_latest/dashboard_provider.dart index f1a92f54..cc39807f 100644 --- a/lib/dashboard_latest/dashboard_provider.dart +++ b/lib/dashboard_latest/dashboard_provider.dart @@ -106,13 +106,22 @@ class DashBoardProvider extends ChangeNotifier { isAllCountLoading = true; notifyListeners(); String url = ''; - if (usersType == UsersTypes.qualityUser) { - url = URLs.qaAuditorCount; - } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { - url = URLs.engineerDashboardCountUrl; - } else { - url = URLs.nurseDashboardCountUrl; - } + + // if (usersType == UsersTypes.qualityUser) { + // url = URLs.qaAuditorCount; + // } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { + // url = URLs.engineerDashboardCountUrl; + // } else { + // url = URLs.nurseDashboardCountUrl; + // } + final urlMap = { + UsersTypes.qualityUser: URLs.qaAuditorCount, + UsersTypes.commissioningEngineer: URLs.commissioningEngineerCount, + UsersTypes.engineer: URLs.engineerDashboardCountUrl, + UsersTypes.assessor: URLs.engineerDashboardCountUrl, + UsersTypes.assessorTl: URLs.engineerDashboardCountUrl, + }; + url = urlMap[usersType] ?? URLs.nurseDashboardCountUrl; Response response; try { response = await ApiManager.instance.post(url, body: {}); @@ -235,6 +244,32 @@ class DashBoardProvider extends ChangeNotifier { } } + String getDashboardUrl({ + required UsersTypes usersType, + int? status, + int? tabId, + }) { + switch (usersType) { + case UsersTypes.qualityUser: + return URLs.qaAuditorDetails; + case UsersTypes.commissioningEngineer: + return URLs.commissioningEngineerDetails; + case UsersTypes.engineer: + case UsersTypes.assessor: + case UsersTypes.assessorTl: + if (status == 0) { + return URLs.engineerDashboardUpcoming; + } else if (status == 1 && tabId == 1) { + return URLs.engineerDashboardNotAssignDetails; + } else { + // status == 1 && tabId == 2 OR any other case + return URLs.engineerDashboardDetailsUrl; + } + default: + return URLs.nurseDashboardDetailsUrl; + } + } + Future getRequestDetail({bool showLoader = true, required UsersTypes usersType, int? status, bool isHighPriority = false, bool isOverdue = false, String? date, int? tabId}) async { if (showLoader) { isDetailLoading = showLoader; @@ -243,25 +278,26 @@ class DashBoardProvider extends ChangeNotifier { Response response; String url = ''; + // if (usersType == UsersTypes.qualityUser) { + // url = URLs.qaAuditorDetails; + // } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { + // //need to check pagination for not assigned task @waseem. + // + // //these checks are to call different apis for dashboard for engineer... + // if (status == 0) { + // url = URLs.engineerDashboardUpcoming; + // } else if (status == 1 && tabId == 1) { + // url = URLs.engineerDashboardNotAssignDetails; + // } else if (status == 1 && tabId == 2) { + // url = URLs.engineerDashboardDetailsUrl; + // } else { + // url = URLs.engineerDashboardDetailsUrl; + // } + // } else { + // url = URLs.nurseDashboardDetailsUrl; + // } + url = getDashboardUrl(usersType: usersType, status: status, tabId: tabId); - if (usersType == UsersTypes.qualityUser) { - url = URLs.qaAuditorDetails; - } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) { - //need to check pagination for not assigned task @waseem. - - //these checks are to call different apis for dashboard for engineer... - if (status == 0) { - url = URLs.engineerDashboardUpcoming; - } else if (status == 1 && tabId == 1) { - url = URLs.engineerDashboardNotAssignDetails; - } else if (status == 1 && tabId == 2) { - url = URLs.engineerDashboardDetailsUrl; - } else { - url = URLs.engineerDashboardDetailsUrl; - } - } else { - url = URLs.nurseDashboardDetailsUrl; - } try { Map body = {"pageNumber": pageNum, "pageSize": pageItemNumber}; @@ -383,6 +419,12 @@ class CategoryTabs { tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4)); return tabs; } + if (userType == UsersTypes.commissioningEngineer) { + tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2)); + tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3)); + tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4)); + return tabs; + } tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2)); tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3)); diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart index 747e2080..991a0f81 100644 --- a/lib/extensions/enum_extensions.dart +++ b/lib/extensions/enum_extensions.dart @@ -125,3 +125,9 @@ enum DropDownMatchType { identifier, name, } + + +enum CostCenterType { + costCenter, + serialNumber, +} diff --git a/lib/main.dart b/lib/main.dart index ceff381d..ed84e486 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,6 +28,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart'; @@ -326,6 +327,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()), ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()), ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()), + ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart index cd6b5f13..13238d83 100644 --- a/lib/models/enums/user_types.dart +++ b/lib/models/enums/user_types.dart @@ -4,5 +4,6 @@ enum UsersTypes { nurse, // 1 assessor, assessorTl, - qualityUser + qualityUser, + commissioningEngineer } diff --git a/lib/models/user.dart b/lib/models/user.dart index 5eac8486..a18b67c5 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -108,10 +108,13 @@ class User { return UsersTypes.assessor; case "R-19": // Head Nurse Role return UsersTypes.assessorTl; + //TODO need to confirm why repeat. case "R-3": // Quality User return UsersTypes.qualityUser; case "R-58": // Quality User return UsersTypes.qualityUser; + case "R-201": // Quality User + return UsersTypes.commissioningEngineer; default: return null; } diff --git a/lib/modules/asset_delivery_module/helper_function.dart b/lib/modules/asset_delivery_module/helper_function.dart new file mode 100644 index 00000000..b34a749c --- /dev/null +++ b/lib/modules/asset_delivery_module/helper_function.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart'; +import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; +import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; + +class HelperFunction { + static void attachmentTap({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async { + Lookup? result; + result = await showAttachmentTypeBottomSheet(context); + List list = []; + + if (result != null) { + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + list = await assetDeliveryProvider.getAttachments(tableItemId: deliveryTableItemId, attachmentType: result.value); + Navigator.pop(context); + // if (list.isNotEmpty) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AssetDeliveryAttachmentView( + tableItemId: deliveryTableItemId, + attachmentType: result!.value, + attachmentList: list, + ))); + // } + } + } + + static Future showAttachmentTypeBottomSheet(BuildContext context) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + builder: (_) { + return SafeArea( + top: false, + child: Padding( + padding: const EdgeInsets.only( + top: 16, + left: 16, + right: 16, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + onSelect: (value) { + Navigator.pop(context, value); + }, + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/modules/asset_delivery_module/models/cost_center_model.dart b/lib/modules/asset_delivery_module/models/cost_center_model.dart index 4bbfe9aa..0cacd34a 100644 --- a/lib/modules/asset_delivery_module/models/cost_center_model.dart +++ b/lib/modules/asset_delivery_module/models/cost_center_model.dart @@ -40,11 +40,6 @@ class CostCenterModel { data['id'] = id ?? 0; data['qty'] = quantity; - // data['costCenter'] = costCenter; - // data['acceptedBy'] = acceptedBy; - // data['acceptanceDate'] = acceptanceDate; - // data['acceptedByEmail'] = acceptedByEmail; - // data['acceptedBySignature'] = acceptedBySignature; data['costCenter'] = costCenterName; return data; } diff --git a/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart b/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart new file mode 100644 index 00000000..049abaa4 --- /dev/null +++ b/lib/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart @@ -0,0 +1,53 @@ +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; + +class CostCenterSerialNoFormModel { + List? costCenters; + List? serialNos; + + CostCenterSerialNoFormModel({ + this.costCenters, + this.serialNos, + }); + + // From JSON + CostCenterSerialNoFormModel.fromJson(Map json) { + if (json['costCenters'] != null) { + costCenters = List.from((json['costCenters'] as List).map((e) => CostCenterModel.fromJson(e))); + } + + if (json['serialNos'] != null) { + serialNos = List.from((json['serialNos'] as List).map((e) => SerialNoModel.fromJson(e))); + } + } + + // To JSON + Map toJson() { + return { + 'costCenters': costCenters?.map((e) => e.toJson()).toList() ?? [], + 'serialNos': serialNos?.map((e) => e.toJson()).toList() ?? [], + }; + } +} + + +class SerialNoModel { + int? id; + String? serialNo; + SerialNoModel({ + this.id, + this.serialNo, + }); + SerialNoModel.fromJson(Map json) { + id = json['id'] ?? json['costCenterId']; + serialNo = json['serialNo']; + } + Map toJson() { + final Map data = {}; + data['id'] = id ?? 0; + data['serialNo'] = serialNo; + return data; + } +} + + + diff --git a/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart index 10b45d4f..4d73b496 100644 --- a/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart +++ b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart @@ -1,6 +1,11 @@ +import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; + class DeliveryInspectionFormModel { int? assetDeliveryExternalDeliveryId; String? deliveryInspectionInspectedBy; + InspectionPersonModel? inspectedByModel; + InspectionPersonModel? approvedByModel; + InspectionPersonModel? thirdApprovalModel; DateTime? deliveryInspectionInspectedDateFrom; DateTime? deliveryInspectionInspectedDateTo; num? totalTime; @@ -9,6 +14,9 @@ class DeliveryInspectionFormModel { DeliveryInspectionFormModel({ this.assetDeliveryExternalDeliveryId, this.deliveryInspectionInspectedBy, + this.inspectedByModel, + this.approvedByModel, + this.thirdApprovalModel, this.deliveryInspectionInspectedDateFrom, this.deliveryInspectionInspectedDateTo, this.totalTime, @@ -18,20 +26,32 @@ class DeliveryInspectionFormModel { DeliveryInspectionFormModel.fromJson(Map json) { assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId']; deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy']; - deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']):null; - deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateTo']):null; + inspectedByModel = InspectionPersonModel(name: json['deliveryInspectionInspectedBy'], email: json['deliveryInspectionInspectedByEmail'], signature: json['deliveryInspectionInspectedBySignature']); + approvedByModel = InspectionPersonModel(name: json['deliveryInspectionApprovedBy'], email: json['deliveryInspectionApprovedByEmail'], signature: json['deliveryInspectionApprovedBySignature']); + thirdApprovalModel = + InspectionPersonModel(name: json['deliveryInspectionThirdApproverBy'], email: json['deliveryInspectionThirdApproverByEmail'], signature: json['deliveryInspectionThirdApproverBySignature']); + deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']) : null; + deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateTo']) : null; totalTime = json['totalTime']; deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy']; } +//TODO need to set payload.. Map toJson() { return { 'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId, - 'deliveryInspectionInspectedBy': deliveryInspectionInspectedBy, - 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(), + 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(), 'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(), 'totalTime': totalTime, - 'deliveryInspectionApprovedBy': deliveryInspectionApprovedBy, + 'deliveryInspectionInspectedBy': inspectedByModel?.name, + "deliveryInspectionInspectedBySignature": inspectedByModel?.signature, + "deliveryInspectionInspectedByEmail": inspectedByModel?.email, + 'deliveryInspectionApprovedBy': approvedByModel?.name, + "deliveryInspectionApprovedBySignature": approvedByModel?.signature, + "deliveryInspectionApprovedByEmail": approvedByModel?.email, + "deliveryInspectionThirdApproverBy": thirdApprovalModel?.name, + "deliveryInspectionThirdApproverBySignature": thirdApprovalModel?.signature, + "deliveryInspectionThirdApproverByEmail": thirdApprovalModel?.email, }; } } diff --git a/lib/modules/asset_delivery_module/models/inspection_person_model.dart b/lib/modules/asset_delivery_module/models/inspection_person_model.dart new file mode 100644 index 00000000..8c00357d --- /dev/null +++ b/lib/modules/asset_delivery_module/models/inspection_person_model.dart @@ -0,0 +1,15 @@ +import 'package:flutter/services.dart'; + +class InspectionPersonModel { + String? name; + String? email; + String? signature; + Uint8List? localSignature; + + InspectionPersonModel({ + this.name, + this.email, + this.signature, + this.localSignature, + }); +} diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart index a8834fcc..e98ab0af 100644 --- a/lib/modules/asset_delivery_module/pages/attachment_view.dart +++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart @@ -1,8 +1,10 @@ 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/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; @@ -15,21 +17,20 @@ 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/default_app_bar.dart'; +import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; class AssetDeliveryAttachmentView extends StatefulWidget { - ///Need to check which parm need here. - final int? lineId; final int? tableItemId; - final int? requestId; - final bool? isHmg; + final int? attachmentType; + final List attachmentList; const AssetDeliveryAttachmentView({ super.key, - this.lineId, - this.requestId, + required this.attachmentList, + this.attachmentType, this.tableItemId, - this.isHmg, }); @override @@ -52,15 +53,17 @@ class _AssetDeliveryAttachmentViewState extends State URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []).toShadowContainer( + context, + borderRadius: 20, + padding: 12, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ), + ], + ), + ), FooterActionButton.footerContainer( context: context, child: AppFilledButton( - buttonColor: AppColor.primary10, - label: 'Save'.addTranslation, - maxWidth: true, - onPressed: () async { - List attachement = []; - for (var item in _attachments) { - String fileName = - CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; - attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName)); - } - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - Map payLoad = { - 'assetDeliveryExternalDeliveryId': widget.tableItemId, - 'attachments': attachement, - }; - await assetDeliveryProvider.saveAttachment(payload: payLoad).then((status) async { - Navigator.pop(context); - if (status) { - ///Need to verify need to stay on this page and refresh or go back.. - Navigator.pop(context); - // assetDeliveryProvider.getDeliveryLinesListById( - // itemId: widget.tableItemId, - // ); - } - }); - }), + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: _onSavePressed, + ), ), ], ), ); } + + Future _onSavePressed() async { + final List attachmentPayload = _attachments.map((item) { + final String name = CMRequestUtils.isLocalUrl(item.name ?? '') ? '${item.name?.split("/").last}|${base64Encode(File(item.name!).readAsBytesSync())}' : item.name ?? ''; + + return GenericAttachmentModel( + id: item.id ?? 0, + name: name, + ); + }).toList(); + + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + + final payload = { + 'assetDeliveryExternalDeliveryId': widget.tableItemId, + 'attachments': attachmentPayload, + }; + + final status = await assetDeliveryProvider.saveAttachment(payload: payload); + + Navigator.pop(context); + + if (status) { + Navigator.pop(context); + } + } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart index 3cc0497b..2fdfe356 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -10,6 +8,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; @@ -47,8 +46,9 @@ class CostCenterFormView extends StatefulWidget { } class _CostCenterFormViewState extends State { - List _list = []; + CostCenterSerialNoFormModel formModel = CostCenterSerialNoFormModel(costCenters: [], serialNos: []); late AssetDeliveryProvider assetDeliveryProvider; + CostCenterType _selectedType = CostCenterType.costCenter; @override void initState() { @@ -60,15 +60,20 @@ class _CostCenterFormViewState extends State { } void getInitialData() async { - _list = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( + formModel = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines( lineId: widget.lineId, tableItemId: widget.tableItemId, ); - if (_list.isEmpty) { - _list.add(CostCenterModel( + if (formModel.costCenters!.isEmpty) { + formModel.costCenters!.add(CostCenterModel( id: 0, )); } + // if (formModel.serialNos!.isEmpty) { + // formModel.serialNos!.add(SerialNoModel( + // id: 0, + // )); + // } if (widget.isHmg == true) { CostCenterProvider costCenterProvider = Provider.of(context, listen: false); if (costCenterProvider.items.isEmpty) { @@ -78,21 +83,21 @@ class _CostCenterFormViewState extends State { setState(() {}); } - void _addNewEntry() { + void addItem(List list, T Function() creator) { setState(() { - _list.add(CostCenterModel(costCenter: Lookup())); + list.add(creator()); }); } - void _removeEntry(int index) { + void removeItem(List list, int index) { setState(() { - _list.removeAt(index); + list.removeAt(index); }); } - void _updateModel(int index, void Function(CostCenterModel model) updateList) { + void updateItem(List list, int index, void Function(T item) updater) { setState(() { - updateList(_list[index]); + updater(list[index]); }); } @@ -111,34 +116,9 @@ class _CostCenterFormViewState extends State { ? const CircularProgressIndicator(color: AppColor.primary10).center : Column( children: [ - itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription), - ListView.builder( - itemCount: _list.length + 1, - shrinkWrap: true, - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), - itemBuilder: (context, index) { - if (index == _list.length) { - return AppFilledButton( - label: "Add Cost Center".addTranslation, - maxWidth: true, - textColor: AppColor.textColor(context), - buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, - icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), - showIcon: true, - onPressed: _addNewEntry, - ); - } - return CostCenterItemCard( - model: _list[index], - index: index, - isReadOnly: false, - isHmg: widget.isHmg, - requestId: widget.requestId, - onUpdate: (updateList) => _updateModel(index, updateList), - onRemove: () => _removeEntry(index), - ); - }, - ).expanded, + itemDetails(), + selectionButton(), + _selectedType == CostCenterType.costCenter ? _buildCostCenterList() : _buildSerialNumberList(), FooterActionButton.footerContainer( context: context, child: AppFilledButton( @@ -147,7 +127,9 @@ class _CostCenterFormViewState extends State { maxWidth: true, onPressed: () async { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async { + await assetDeliveryProvider + .saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: formModel.costCenters, serialNoList: formModel.serialNos) + .then((status) async { Navigator.pop(context); if (status) { Navigator.pop(context); @@ -163,40 +145,169 @@ class _CostCenterFormViewState extends State { }), ); } -} -Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Item No'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), - ), - 8.height, - Text( - itemNo ?? '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), - ), - 8.height, - Text( - 'Item Description'.addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + Widget _buildCostCenterList() { + return ListView.builder( + itemCount: formModel.costCenters!.length + 1, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), + itemBuilder: (context, index) { + if (index == formModel.costCenters!.length) { + return AppFilledButton( + label: "Add Cost Center".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: () { + addItem(formModel.costCenters!, () => CostCenterModel(costCenter: Lookup())); + }, + ); + } + + return CostCenterItemCard( + model: formModel.costCenters![index], + index: index, + isReadOnly: false, + isHmg: widget.isHmg, + requestId: widget.requestId, + onUpdate: (update) { + updateItem(formModel.costCenters!, index, update); + }, + onRemove: () { + removeItem(formModel.costCenters!, index); + }, + ); + }, + ).expanded; + } + + Widget _buildSerialNumberList() { + return ListView.builder( + itemCount: formModel.serialNos!.length + 1, + shrinkWrap: true, + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8), + itemBuilder: (context, index) { + if (index == formModel.serialNos!.length) { + return AppFilledButton( + label: "Add Serial Number".addTranslation, + maxWidth: true, + textColor: AppColor.textColor(context), + buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10, + icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)), + showIcon: true, + onPressed: () { + addItem(formModel.serialNos!, () => SerialNoModel()); + }, + ); + } + + return SerialNumberItemCard( + model: formModel.serialNos![index], + onUpdate: (update) { + updateItem(formModel.serialNos!, index, update); + }, + onRemove: () { + removeItem(formModel.serialNos!, index); + }, + ); + }, + ).expanded; + } + + Widget selectionButton() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + children: [ + Expanded( + child: _radioItem( + value: CostCenterType.costCenter, + groupValue: _selectedType, + title: 'Cost Center', + onTap: () { + setState(() { + _selectedType = CostCenterType.costCenter; + }); + }, + ), + ), + Expanded( + child: _radioItem( + value: CostCenterType.serialNumber, + groupValue: _selectedType, + title: 'Serial Number', + onTap: () { + setState(() { + _selectedType = CostCenterType.serialNumber; + }); + }, + ), + ), + ], ), - 8.height, - Text( - itemDescription ?? '-', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ); + } + + Widget _radioItem({ + required CostCenterType value, + required CostCenterType groupValue, + required String title, + required VoidCallback onTap, + }) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: onTap, + child: Row( + children: [ + Radio( + value: value, + groupValue: groupValue, + onChanged: (_) => onTap(), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity.compact, + ), + 4.width, + title.addTranslation.bodyText(context), + ], ), - ], - ).toShadowContainer( - context, - borderRadius: 20, - padding: 12, - showShadow: false, - margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8), - ); + ); + } + + Widget itemDetails() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Item No'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + widget.itemNo ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + 8.height, + Text( + 'Item Description'.addTranslation, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + 8.height, + Text( + widget.itemDescription ?? '-', + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120), + ), + ], + ).toShadowContainer( + context, + borderRadius: 20, + padding: 12, + showShadow: false, + margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8), + ); + } } class CostCenterItemCard extends StatelessWidget { @@ -294,3 +405,53 @@ class CostCenterItemCard extends StatelessWidget { ).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12)).paddingOnly(bottom: 12); } } + +class SerialNumberItemCard extends StatelessWidget { + final SerialNoModel model; + final VoidCallback onRemove; + final void Function(void Function(SerialNoModel model)) onUpdate; + + const SerialNumberItemCard({ + super.key, + required this.model, + required this.onRemove, + required this.onUpdate, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + 'Serial Number'.addTranslation.bodyText(context), + Container( + height: 28, + width: 28, + padding: const EdgeInsets.all(6), + child: "trash".toSvgAsset(height: 20, width: 20), + ).onPress(onRemove), + ], + ), + 8.height, + AppTextFormField( + labelText: 'Serial Number'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.serialNo ?? '', + textAlign: TextAlign.center, + showShadow: false, + onChange: (value) { + model.serialNo = value; + }, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ) + .toShadowContainer( + context, + paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + ) + .paddingOnly(bottom: 12); + } +} diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index 3ef8c0a0..c6918f74 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -1,5 +1,5 @@ -import 'dart:developer'; - +import 'dart:convert'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -7,21 +7,26 @@ 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/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart'; import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart'; +import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.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_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/single_item_drop_down_menu.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; @@ -129,7 +134,13 @@ class _DeliveryInspectionFormViewState extends State child: !viewOnly ? Column( children: [ - AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap), + AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Attachments'.addTranslation, + maxWidth: true, + onPressed: () { + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + }), 16.height, Row( children: [ @@ -207,56 +218,109 @@ class _DeliveryInspectionFormViewState extends State Widget inspectionDetailsForm() { return Column( children: [ - if (widget.requestModel?.isHMG == true) ...[ - OracleUserAutoCompleteField( - clearAfterPick: false, - initialValue: model.deliveryInspectionInspectedBy ?? '', - label: 'Inspected by'.addTranslation, - onPick: (value) { - model.deliveryInspectionInspectedBy = value.fullName; - setState(() {}); - }, - onChanged: (value) {}, - ), - 8.height, - OracleUserAutoCompleteField( - clearAfterPick: false, - initialValue: model.deliveryInspectionApprovedBy ?? '', - label: 'Approved by'.addTranslation, - onChanged: (value) {}, - onPick: (value) { - model.deliveryInspectionApprovedBy = value.fullName; - setState(() {}); - }, - ), - ] //No HMG user free text insted of dropdown ... - else ...[ - AppTextFormField( - labelText: 'Inspected by'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: model.deliveryInspectionInspectedBy ?? '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - onChange: (value) { - model.deliveryInspectionInspectedBy = value; - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - AppTextFormField( - labelText: 'Approved by'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - initialValue: model.deliveryInspectionApprovedBy ?? '', - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - showShadow: false, - onChange: (value) { - model.deliveryInspectionApprovedBy = value; + _inspectionTile( + title: 'Inspected by'.addTranslation, + model: model.inspectedByModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Inspected by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.inspectedByModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.inspectedByModel = result); + } + }, + ), + + 8.height, + _inspectionTile( + title: 'Approved by'.addTranslation, + model: model.approvedByModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Approved by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.approvedByModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.approvedByModel = result); + } + }, + ), + if (widget.requestModel?.paymentTerm?.value == 2) ...[ + _inspectionTile( + title: 'Third Approved by'.addTranslation, + model: model.thirdApprovalModel, + isHmg: widget.requestModel?.isHMG == true, + onTap: () async { + final result = await showInspectionBottomSheet( + context, + title: 'Third Approved by'.addTranslation, + isHmg: widget.requestModel?.isHMG == true, + initialModel: model.thirdApprovalModel ?? InspectionPersonModel(), + ); + if (result != null) { + setState(() => model.thirdApprovalModel = result); + } }, - style: Theme.of(context).textTheme.titleMedium, ), ], + + // if (widget.requestModel?.isHMG == true) ...[ + // OracleUserAutoCompleteField( + // clearAfterPick: false, + // initialValue: model.deliveryInspectionInspectedBy ?? '', + // label: 'Inspected by'.addTranslation, + // onPick: (value) { + // model.deliveryInspectionInspectedBy = value.fullName; + // setState(() {}); + // }, + // onChanged: (value) {}, + // ), + // 8.height, + // OracleUserAutoCompleteField( + // clearAfterPick: false, + // initialValue: model.deliveryInspectionApprovedBy ?? '', + // label: 'Approved by'.addTranslation, + // onChanged: (value) {}, + // onPick: (value) { + // model.deliveryInspectionApprovedBy = value.fullName; + // setState(() {}); + // }, + // ), + // ] //No HMG user free text insted of dropdown ... + // else ...[ + // AppTextFormField( + // labelText: 'Inspected by'.addTranslation, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: model.deliveryInspectionInspectedBy ?? '', + // textAlign: TextAlign.center, + // labelStyle: AppTextStyles.textFieldLabelStyle, + // showShadow: false, + // onChange: (value) { + // model.deliveryInspectionInspectedBy = value; + // }, + // style: Theme.of(context).textTheme.titleMedium, + // ), + // 8.height, + // AppTextFormField( + // labelText: 'Approved by'.addTranslation, + // backgroundColor: AppColor.fieldBgColor(context), + // initialValue: model.deliveryInspectionApprovedBy ?? '', + // textAlign: TextAlign.center, + // labelStyle: AppTextStyles.textFieldLabelStyle, + // showShadow: false, + // onChange: (value) { + // model.deliveryInspectionApprovedBy = value; + // }, + // style: Theme.of(context).textTheme.titleMedium, + // ), + // ], 8.height, ADatePicker( label: 'Inspected Date/Time From'.addTranslation, @@ -417,13 +481,69 @@ class _DeliveryInspectionFormViewState extends State ); } - void _attachmentTap() async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + Widget _inspectionTile({ + required String title, + InspectionPersonModel? model, + required bool isHmg, + required VoidCallback onTap, + }) { + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: AppTextStyles.textFieldLabelStyle), + 6.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + model?.name?.isNotEmpty == true ? model!.name! : 'Tap to add'.addTranslation, + style: AppTextStyles.bodyText, + ), + + ///Need to display other info as well + // Text( + // model?.email?.isNotEmpty == true + // ? model!.email! + // : '', + // style: AppTextStyles.bodyText, + // ), + ], + ), + ], + ), + ], + ), + ), + ); + } + + Future showAttachmentTypePicker() { + return showDialog( + context: context, + builder: (_) { + return AlertDialog( + content: SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + showAsFullScreenDialog: false, + onSelect: (value) { + Navigator.pop(context, value); + }, + ), + ); + }, + ); } void _cancelTap() async { @@ -469,4 +589,40 @@ class _DeliveryInspectionFormViewState extends State } }); } + + Future showInspectionBottomSheet( + BuildContext context, { + required String title, + required bool isHmg, + required InspectionPersonModel initialModel, + }) { + return showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + builder: (_) { + if (initialModel.localSignature == null && initialModel.signature != null) { + initialModel.localSignature = signatureFromString(initialModel.signature); + } + return InspectionPersonBottomSheet( + title: title, + isHmg: isHmg, + model: InspectionPersonModel( + name: initialModel.name, + email: initialModel.email, + signature: initialModel.signature, + localSignature: initialModel.localSignature, + ), + ); + }, + ); + } + + Uint8List? signatureFromString(String? value) { + if (value == null || !value.contains('|')) return null; + final base64Part = value.split('|').last; + return base64Decode(base64Part); + } } diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart new file mode 100644 index 00000000..bd81f92a --- /dev/null +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.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/modules/asset_delivery_module/models/inspection_person_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.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/views/widgets/e_signature/e_signature.dart'; + +class InspectionPersonBottomSheet extends StatefulWidget { + final String title; + bool isHmg; + final InspectionPersonModel model; + + InspectionPersonBottomSheet({ + super.key, + required this.title, + required this.isHmg, + required this.model, + }); + + @override + State createState() => _InspectionPersonBottomSheetState(); +} + +class _InspectionPersonBottomSheetState extends State { + late InspectionPersonModel _model; + + late TextEditingController nameController; + late TextEditingController emailController; + + @override + void initState() { + super.initState(); + + _model = InspectionPersonModel(name: widget.model.name, email: widget.model.email, signature: widget.model.signature, localSignature: widget.model.localSignature); + nameController = TextEditingController(text: _model.name ?? ''); + emailController = TextEditingController(text: _model.email ?? ''); + widget.isHmg = true; + log('isHmg = ${widget.isHmg}'); + } + + @override + void dispose() { + nameController.dispose(); + emailController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + child: Padding( + padding: EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(widget.title, style: Theme.of(context).textTheme.titleLarge), + 16.height, + if (widget.isHmg) + OracleUserAutoCompleteField( + clearAfterPick: false, + initialValue: _model.name ?? '', + label: 'Name'.addTranslation, + onPick: (value) { + _model.name = value.fullName; + nameController.text = value.fullName ?? ''; + setState(() {}); + }, + ) + else + AppTextFormField( + labelText: 'Name'.addTranslation, + controller: nameController, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + onChange: (v) { + _model.name = v; + setState(() {}); + }, + ), + 12.height, + AppTextFormField( + labelText: 'Email'.addTranslation, + controller: emailController, + textInputType: TextInputType.emailAddress, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + style: Theme.of(context).textTheme.titleMedium, + onChange: (v) { + setState(() { + _model.email = v; + }); + }, + ), + 12.height, + ESignature( + title: '', + oldSignature: _model.localSignature == null ? _model.signature : null, + newSignature: _model.localSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onChange: (signature) { + if (signature.isEmpty) return; + setState(() { + _model.localSignature = signature; + _model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + onSaved: (signature) { + if (signature == null || signature.isEmpty) return; + setState(() { + _model.localSignature = signature; + _model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}"; + }); + }, + ), + 20.height, + AppFilledButton( + label: context.translation.save, + maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + _model.name = nameController.text.trim(); + _model.email = emailController.text.trim(); + Navigator.pop(context, _model); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart index 5accb0ae..92979620 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart @@ -5,6 +5,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/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; @@ -156,12 +157,7 @@ class _EndUserCostCenterLIstViewState extends State { } void _attachmentTap() async { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); } void _cancelTap() async { diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart index 11105480..b4c6d505 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart @@ -8,6 +8,7 @@ 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/lookup.dart'; +import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; @@ -224,12 +225,13 @@ class _TechnicalInspectionLinesListViewState extends State AssetDeliveryAttachmentView( - tableItemId: widget.deliveryTableModel.id, - ))); + HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id); + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => AssetDeliveryAttachmentView( + // tableItemId: widget.deliveryTableModel.id, + // ))); } void _cancelTap() async { diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart index a9dedb0d..c01a4c2c 100644 --- a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -11,6 +11,7 @@ import 'package:test_sa/models/new_models/floor.dart'; import 'package:test_sa/models/new_models/room_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart'; +import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart'; @@ -171,33 +172,38 @@ class AssetDeliveryProvider extends ChangeNotifier { } } - Future> getAssetDeliveryCostCenterListForLines({int? lineId, int? tableItemId}) async { - List costCenterList = []; + Future getAssetDeliveryCostCenterListForLines({ + int? lineId, + int? tableItemId, + }) async { + CostCenterSerialNoFormModel costCenterSerialNoFormModel = CostCenterSerialNoFormModel(); try { isLoading = true; notifyListeners(); + final response = await ApiManager.instance.get( - "${URLs.getCostCenterListToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", + "${URLs.getCostCenterAndSerialNoToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId", ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { final jsonData = json.decode(response.body)["data"]; - if (jsonData is List) { - costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList(); - } + costCenterSerialNoFormModel = CostCenterSerialNoFormModel.fromJson(jsonData); } else { - costCenterList = []; + costCenterSerialNoFormModel.costCenters = []; + costCenterSerialNoFormModel.serialNos = []; } - isLoading = false; - notifyListeners(); - return costCenterList; } catch (e) { log("get Delivery Lines List [error] : $e"); + costCenterSerialNoFormModel.costCenters = []; + costCenterSerialNoFormModel.serialNos = []; + } finally { isLoading = false; - costCenterList = []; notifyListeners(); - return costCenterList; } + + return costCenterSerialNoFormModel; } Future addNewDelivery({ @@ -253,15 +259,18 @@ class AssetDeliveryProvider extends ChangeNotifier { int? tableItemId, int? lineId, List? list, + List? serialNoList, }) async { isLoading = true; Map payload = { "assetDeliveryExternalDeliveryId": tableItemId, "assetDeliveryExternalDetailId": lineId, "costCenters": list?.map((x) => x.toJson()).toList(), + if (serialNoList != null && serialNoList.isNotEmpty) + "serialNos": serialNoList.map((x) => x.toJson()).toList(), }; try { - final response = await ApiManager.instance.post(URLs.saveCostCenterToLineDeliveryInspection, body: payload); + final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; @@ -421,10 +430,11 @@ class AssetDeliveryProvider extends ChangeNotifier { Future> getAttachments({ num? tableItemId, + num? attachmentType, }) async { try { isLoading = true; - final response = await ApiManager.instance.get("${URLs.getAttachments}?assetDeliveryExternalDeliveryId=$tableItemId"); + final response = await ApiManager.instance.get("${URLs.getAttachments}?attachmentDocTypeValue=$attachmentType&assetDeliveryExternalDeliveryId=$tableItemId"); List list = []; if (response.statusCode >= 200 && response.statusCode < 300) { isLoading = false; diff --git a/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart new file mode 100644 index 00000000..2ef16d0b --- /dev/null +++ b/lib/modules/asset_delivery_module/provider/attachment_type_provider.dart @@ -0,0 +1,33 @@ +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 AttachmentTypeLookupProvider extends LoadingListNotifier { + @override + Future getData({int? id}) async { + if (loading == true) return -2; + loading = true; + notifyListeners(); + loading = true; + notifyListeners(); + try { + Response response = await ApiManager.instance.get(URLs.attachmentTypeLookup); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List categoriesListJson = json.decode(response.body)["data"]; + items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList(); + } + loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + loading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} 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 ea9963d2..06482a0f 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 @@ -106,6 +106,12 @@ class _AllRequestsFilterPageState extends State { types['Equipment Internal Audit'] = 10; types['System Internal Audit'] = 11; } + if (context.userProvider.isCommissioningEngineer) { + ///TODO need to check what other requests type needed here. + types = { + 'Asset Delivery': 13, + }; + } final statuses = { "All WO": 0, 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 0a31b856..52c35338 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 @@ -69,7 +69,7 @@ class _MyRequestsPageState extends State { requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(11, 'System Internal Audit')); //Need to be added for new user role commissioning engineer - requestsList.add(Request(13, "Asset Delivery")); + // requestsList.add(Request(13, "Asset Delivery")); } requestsList.add(Request(12, "Loan Equipment")); @@ -80,6 +80,13 @@ class _MyRequestsPageState extends State { Request(9, 'TRAF'), ]; } + if (context.userProvider.isCommissioningEngineer) { + ///TODO need to show only allowed ids for all workOrder + requestsList = [ + Request(null, context.translation.allWorkOrder), + Request(13, "Asset Delivery"), + ]; + } if (context.userProvider.isQualityUser) { requestsList = [ Request(null, context.translation.allWorkOrder),