diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html
new file mode 100644
index 00000000..d59d3b0f
--- /dev/null
+++ b/android/build/reports/problems/problems-report.html
@@ -0,0 +1,663 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gradle Configuration Cache
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
diff --git a/assets/images/history_icon.svg b/assets/images/history_icon.svg
new file mode 100644
index 00000000..89ab3df8
--- /dev/null
+++ b/assets/images/history_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/images/web_link_icon.svg b/assets/images/web_link_icon.svg
new file mode 100644
index 00000000..9d77b3f7
--- /dev/null
+++ b/assets/images/web_link_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart
index ed077246..eed578cf 100644
--- a/lib/controllers/api_routes/urls.dart
+++ b/lib/controllers/api_routes/urls.dart
@@ -1,7 +1,7 @@
class URLs {
URLs._();
- static const String appReleaseBuildNumber = "31";
+ static const String appReleaseBuildNumber = "32";
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
@@ -18,6 +18,7 @@ class URLs {
static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis
static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis
+ static const String resetMessageCount = "$chatHubUrlApi/userChatHistory/AckMessages"; // new V2 apis
static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis
static String _host = host1;
@@ -66,9 +67,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';
@@ -393,4 +396,61 @@ class URLs {
static get getLoanById => '$_baseUrl/Loan/GetLoanById';
static get addLoan => '$_baseUrl/Loan/AddLoan';
+
+ //Asset Delivery Module
+ static get getAssetDeliveryDetailsById => '$_baseUrl/AssetDeliveryExternal/GetAssetDeliveryExternalById';
+
+ static get getAssetDeliveryTableListById => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveriesByMasterId';
+
+ static get addNewDelivery => '$_baseUrl/AssetDeliveryExternalDelivery/AddNewDelivery';
+
+ static get changeDeliveryStatusToCancel => '$_baseUrl/AssetDeliveryExternalDelivery/ChangeStatusDeliveryToCancel';
+
+ static get changeDeliveryStatus => '$_baseUrl/AssetDeliveryExternalDelivery/ChangeStatusDelivery';
+
+ static get getAssetDeliveryInspectionData => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetAssetDeliveryExternalDeliveryInspectionByDeliveryId';
+
+ static get getOracleUserList => '$_baseUrl/AssetDeliveryExternal/GetEmployeesFromOracle';
+
+ 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';
+ static get getTechnicalInspectionByDetailId => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetTechnicalInspectionByDetailId';
+ static get powerSupplyTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=527";
+ static get saveTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspection";
+ static get getTechnicalInspectionParentData => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetTechnicalInspectionItemByCostCenterId";
+ static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal";
+ static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal";
+ static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem";
+ static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachmentsBasedOnType";
+ static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save";
+ //End user Acceptance...
+ static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter";
+ static get getCostCenterAssetList => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetItemByCostCenter";
+ 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";
+
+ //Medical Gas Request..
+// 4004
+ static get orderTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4004";
+ // static get itemTypeLookUp => "$_baseUrl/Lookups/GetLookup?lookupEnum=4005";
+ static get itemTypeLookUp => "$_baseUrl/MedicalGas/GetItemTypeLookup?lookupEnum=4002";
+ static get getMedicalGasSupplierList => "$_baseUrl/MedicalGas/GetMedicalGasSupplierAsync";
+ static get getMedicalGasInfoBySupplier => "$_baseUrl/MedicalGas/GetMedicalGasInfoBySupplierAsync";
+ static get addMedicalGasRequest => "$_baseUrl/MedicalGas/AddUpdateMedicalGasRequestAsync";
+ static get getMedicalGasById => "$_baseUrl/MedicalGas/GetMedicalGasRequestByIdAsync";
+ static get updateDeliveryNote => "$_baseUrl/MedicalGas/MedicalGasRequestDeliveryNotesAsync";
+
+
+
}
diff --git a/lib/controllers/notification/firebase_notification_manger.dart b/lib/controllers/notification/firebase_notification_manger.dart
index bc011827..243e8a57 100644
--- a/lib/controllers/notification/firebase_notification_manger.dart
+++ b/lib/controllers/notification/firebase_notification_manger.dart
@@ -1,4 +1,5 @@
import 'dart:convert';
+import 'dart:developer';
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
@@ -13,6 +14,7 @@ import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart';
import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart';
import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart';
+import 'package:test_sa/modules/tm_module/tasks/task_request_detail_view.dart';
import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@@ -88,6 +90,44 @@ class FirebaseNotificationManger {
String? transactionType = messageData["transactionType"]?.toString();
+ if (transactionType == null) {
+ return;
+ } else if (transactionType == "17" && messageData["requestType"] == "chat") {
+ int moduleId = int.parse(messageData["moduleId"].toString());
+ int requestNumber = int.parse(messageData["requestNumber"].toString());
+
+ switch (moduleId) {
+ case 1: // cm
+ serviceClass = CMDetailPage(requestId: requestNumber, moduleId: moduleId);
+ break;
+ case 2: // gas refill
+ serviceClass = GasRefillDetailsPage(
+ priority: messageData["priority"],
+ date: messageData["createdOn"],
+ moduleId: moduleId,
+ model: GasRefillModel(id: requestNumber),
+ );
+ break;
+ case 3: //transfer
+ serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: requestNumber), moduleId: moduleId);
+ break;
+ case 6: // task
+ serviceClass = TaskRequestDetailsView(
+ taskId: requestNumber,
+ moduleId: moduleId,
+ // requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ),
+ );
+ // ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
+ break;
+
+ default:
+ serviceClass = const Scaffold(body: Center(child: NoDataFound()));
+ }
+
+ Navigator.of(context).push(MaterialPageRoute(builder: (_) => serviceClass!));
+ return;
+ }
+
// PPM=1,
// ServiceRequestEngineer = 3,
// AssetTransfer=7,
@@ -101,13 +141,13 @@ class FirebaseNotificationManger {
break;
//these three request are same corrective maintenance....
case "3":
- serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()));
+ serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break;
case "8":
- serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()));
+ serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break;
case "11":
- serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()));
+ serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break;
case "7":
serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString())), moduleId: 3);
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/devices_provider.dart b/lib/controllers/providers/api/devices_provider.dart
index 3d031a61..ab196c11 100644
--- a/lib/controllers/providers/api/devices_provider.dart
+++ b/lib/controllers/providers/api/devices_provider.dart
@@ -1,4 +1,5 @@
import 'dart:convert';
+import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -10,6 +11,7 @@ import 'package:test_sa/models/device/asset_by_id_model.dart';
import 'package:test_sa/models/device/asset_search.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/user.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inpection_asset_model.dart';
import '../../../models/device/asset.dart';
@@ -38,6 +40,7 @@ class AssetProvider extends ChangeNotifier {
List _devices = [];
List _searchDevices = [];
+ List technicalInspectionAsset= [];
List get devices => _devices;
@@ -99,6 +102,49 @@ class AssetProvider extends ChangeNotifier {
return response.statusCode;
}
+ Future getAssetsForAssetDelivery({DeviceSearch? search, bool isSearchBy = false, int? lineId}) async {
+ if (_loading == true) return -2;
+ _loading = true;
+ notifyListeners();
+ late Response response;
+ try {
+ final Map body = {
+ "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber,
+ "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1,
+
+ ///Uncommit this after testing...
+ "assetDeliveryExternalDetailId": lineId,
+ "assetName": search?.assetName,
+
+ // "assetDeliveryExternalDetailId": 2,
+ // "assetName": "Treatment Center Intego - Dental Chair",
+ "assetNumber": search?.assetNo,
+ "model": search?.model,
+ "manufacturer": search?.manufacturer,
+ };
+ response = await ApiManager.instance.post(URLs.getAssetFromInternalTechnicalInspection, body: body);
+ } catch (error) {
+ _loading = false;
+ _stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ _stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ List equipmentListJson = json.decode(response.body)["data"];
+ var dList = equipmentListJson.map((asset) => TechnicalInspectionAssetBasicInfoModel.fromJson(asset)).toList() ?? [];
+ log('dlist ${dList.length}');
+
+ technicalInspectionAsset.addAll(dList);
+ nextPage = true;
+ } else {
+ nextPage = false;
+ }
+ _loading = false;
+ notifyListeners();
+ return response.statusCode;
+ }
+
Future getAssetById(int assetId, AppLocalizations appLocalizations) async {
late Response response;
try {
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/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart
index 987e76cd..bf9b5a71 100644
--- a/lib/dashboard_latest/dashboard_view.dart
+++ b/lib/dashboard_latest/dashboard_view.dart
@@ -73,14 +73,14 @@ class _DashboardViewState extends State {
// await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef');
// await dashBoardProvider.getDashBoardCount(usersType: user.type!);
// await getAllRequests();
- if (isFCM) {
- FirebaseNotificationManger.initialized(context);
- NotificationManger.initialisation((notificationDetails) {
- FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
- }, (id, title, body, payload) async {});
-
- isFCM = false;
- }
+ // if (isFCM) {
+ // FirebaseNotificationManger.initialized(context);
+ // NotificationManger.initialisation((notificationDetails) {
+ // FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
+ // }, (id, title, body, payload) async {});
+ //
+ // isFCM = false;
+ // }
});
}
diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart
index d0e5d156..9ae0e6ce 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/asset_delivery_module/pages/asset_delivery_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_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/task_request_item_view.dart';
@@ -62,6 +63,8 @@ class RequestCategoryList extends StatelessWidget {
return EquipmentInternalAuditItemView(requestData: request);
case 11:
return EquipmentInternalAuditItemView(requestData: request);
+ case 13:
+ return AssetDeliveryItemView(requestData: request);
default:
return Container(
height: 100,
diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart
index f85af74c..96e79211 100644
--- a/lib/extensions/context_extension.dart
+++ b/lib/extensions/context_extension.dart
@@ -29,11 +29,9 @@ extension BuildContextExtension on BuildContext {
return isTablet;
}
-
-
void showConfirmDialog(String message, {String? title, VoidCallback? onTap, String? okTitle}) => showDialog(
context: this,
- builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title,okTitle: okTitle),
+ builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title, okTitle: okTitle),
);
Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet(
diff --git a/lib/extensions/enum_extensions.dart b/lib/extensions/enum_extensions.dart
index c6d10640..24d0a479 100644
--- a/lib/extensions/enum_extensions.dart
+++ b/lib/extensions/enum_extensions.dart
@@ -121,3 +121,37 @@ extension StringExtensionsRecurrentTaskInpesctionDataType on String {
}
}
}
+
+
+extension IntExtensionsAssetDeliveryStage on int {
+ AssetDeliveryStageEnum toAssetDeliveryStageEnum() {
+ switch (this) {
+ case 2:
+ return AssetDeliveryStageEnum.deliveryInspection;
+ case 3:
+ return AssetDeliveryStageEnum.technicalInspection;
+ case 4:
+ return AssetDeliveryStageEnum.endUserAcceptance;
+ default:
+ return AssetDeliveryStageEnum.other;
+ }
+ }
+}
+
+
+enum DropDownMatchType {
+ identifier,
+ name,
+}
+
+
+enum CostCenterType {
+ costCenter,
+ serialNumber,
+}
+enum AssetDeliveryStageEnum {
+ deliveryInspection,
+ technicalInspection,
+ endUserAcceptance,
+ other,
+}
diff --git a/lib/main.dart b/lib/main.dart
index aedb7794..20701c5c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -27,6 +27,12 @@ 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_last_calls_provider.dart';
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';
+import 'package:test_sa/modules/asset_delivery_module/provider/power_supply_type_provider.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/cm_detail_provider.dart';
import 'package:test_sa/modules/cm_module/create_cm_request.dart';
@@ -45,6 +51,9 @@ import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart';
import 'package:test_sa/modules/loan_module/provider/loan_provider.dart';
import 'package:test_sa/modules/loan_module/provider/medical_department_provider.dart';
import 'package:test_sa/modules/medical_gas_inspection/create_medical_gas_request_page.dart';
+import 'package:test_sa/modules/medical_gas_inspection/providers/item_type_provider.dart';
+import 'package:test_sa/modules/medical_gas_inspection/providers/medical_gas_inspection_provider.dart';
+import 'package:test_sa/modules/medical_gas_inspection/providers/order_type_provider.dart';
import 'package:test_sa/modules/tm_module/gas_refill/create_gas_refill_request.dart';
import 'package:test_sa/modules/tm_module/gas_refill/update_gas_refill_request.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
@@ -113,6 +122,7 @@ import 'dashboard_latest/dashboard_provider.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 'modules/cx_module/survey/survey_provider.dart';
+import 'modules/medical_gas_inspection/providers/medical_gas_supplier_provider.dart';
import 'modules/tm_module/device_transfer/create_device_transfer_request.dart';
import 'modules/tm_module/device_transfer/device_filter_screen.dart';
import 'modules/tm_module/device_transfer/device_search_screen.dart';
@@ -134,6 +144,7 @@ import 'providers/service_request_providers/reject_reason_provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
// HttpOverrides.global = MyHttpOverrides(); // for later use.
_configureLocalTimeZone();
NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {});
@@ -320,6 +331,16 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => LoanProvider()),
ChangeNotifierProvider(create: (_) => LoanPeriodProvider()),
ChangeNotifierProvider(create: (_) => MedicalDepartmentProvider()),
+ ChangeNotifierProvider(create: (_) => AssetDeliveryProvider()),
+ ChangeNotifierProvider(create: (_) => CostCenterProvider()),
+ ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()),
+ ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()),
+ ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()),
+ ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider()),
+ ChangeNotifierProvider(create: (_) => MedicalGasOrderTypeProvider()),
+ ChangeNotifierProvider(create: (_) => MedicalGasItemTypeProvider()),
+ ChangeNotifierProvider(create: (_) => MedicalGasInspectionProvider()),
+ ChangeNotifierProvider(create: (_) => MedicalGasSupplierProvider()),
ChangeNotifierProvider(create: (_) => DemoProvider()),
ChangeNotifierProvider(create: (_) => DemoPeriodLookupProvider()),
],
@@ -389,6 +410,7 @@ class MyApp extends StatelessWidget {
UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(),
UpdateSystemInternalAuditPage.id: (_) => UpdateSystemInternalAuditPage(),
CreateLoanRequestPage.id: (_) => CreateLoanRequestPage(),
+ CreateMedicalGasRequestPage.id: (_) => CreateMedicalGasRequestPage(),
// SwipeSuccessView.routeName: (_) => const SwipeSuccessView(),
// SwipeHistoryView.routeName: (_) => const SwipeHistoryView(),
diff --git a/lib/models/all_requests_and_count_model.dart b/lib/models/all_requests_and_count_model.dart
index e980e164..95f19030 100644
--- a/lib/models/all_requests_and_count_model.dart
+++ b/lib/models/all_requests_and_count_model.dart
@@ -128,6 +128,8 @@ class RequestsDetails {
String? date;
String? siteTransferFrom;
String? siteTransferTo;
+ String? poInternal;
+ String? poExternal;
int? transactionType;
int? numberOfAssets;
int? numberOfSites;
@@ -156,6 +158,8 @@ class RequestsDetails {
this.code,
this.siteTransferFrom,
this.siteTransferTo,
+ this.poInternal,
+ this.poExternal,
this.date,
this.transactionType});
@@ -182,6 +186,8 @@ class RequestsDetails {
assetTransferTo = json['assetTransferTo'];
code = json['code'];
date = json['date'];
+ poInternal = json['poInternal'];
+ poExternal = json['poExternal'];
siteTransferFrom = json['siteTransferFrom'];
siteTransferTo = json['siteTransferTo'];
transactionType = json['transactionType'];
diff --git a/lib/models/device/asset_search.dart b/lib/models/device/asset_search.dart
index f311b208..1a70196b 100644
--- a/lib/models/device/asset_search.dart
+++ b/lib/models/device/asset_search.dart
@@ -1,6 +1,7 @@
import 'package:test_sa/models/lookup.dart';
class DeviceSearch {
+
DeviceSearch(
{this.code,
this.assetSerialNumber,
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/generic_attachment_model.dart b/lib/models/generic_attachment_model.dart
index 1d3cd5ea..c0c2b4cf 100644
--- a/lib/models/generic_attachment_model.dart
+++ b/lib/models/generic_attachment_model.dart
@@ -8,7 +8,6 @@ class GenericAttachmentModel {
String ?createdBy;
String? originalName;
GenericAttachmentModel.fromJson(Map json) {
- print('created by here is ${json['createdBy']}');
id = json['id'];
name = json['name'];
createdBy = json['createdBy'];
diff --git a/lib/models/lookup.dart b/lib/models/lookup.dart
index 844e46df..1af16028 100644
--- a/lib/models/lookup.dart
+++ b/lib/models/lookup.dart
@@ -7,9 +7,10 @@ class Lookup extends Base {
int? id; // Now nullable
int? value; // Now nullable
WorkOrderNextStepEnum? workOrderNextStepEnum; // Now nullable
+ AssetDeliveryStageEnum? assetDeliveryStageEnum; // Now nullable
String? name; // Now nullable
- Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum}) : super(identifier: id?.toString(), name: name);
+ Lookup({this.id, this.value, this.name, this.workOrderNextStepEnum, this.assetDeliveryStageEnum}) : super(identifier: id?.toString(), name: name);
@override
bool operator ==(Object other) => identical(this, other) || other is Lookup && ((value != null && value == other.value) || (id != null && id == other.id));
@@ -38,10 +39,11 @@ class Lookup extends Base {
// }
factory Lookup.fromJson(Map? parsedJson) {
- if(parsedJson==null) return Lookup();
+ if (parsedJson == null) return Lookup();
return Lookup(
name: parsedJson["name"],
workOrderNextStepEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toWorkOrderNextStepEnum(),
+ assetDeliveryStageEnum: parsedJson["value"] == null ? null : (parsedJson["value"] as int).toAssetDeliveryStageEnum(),
id: parsedJson["id"],
value: parsedJson["value"],
);
diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart
index 093019b2..93c868a1 100644
--- a/lib/models/new_models/dashboard_detail.dart
+++ b/lib/models/new_models/dashboard_detail.dart
@@ -55,6 +55,9 @@ class Data {
String? assetNumber;
String? requestTypeName;
String? requestNo;
+ String? requestType;
+ String? poInternal;
+ String? poExternal;
int? transactionNo;
int? numberOfSites;
int? numberOfAssets;
@@ -75,6 +78,9 @@ class Data {
this.assetNumber,
this.requestTypeName,
this.requestNo,
+ this.requestType,
+ this.poExternal,
+ this.poInternal,
this.transactionNo});
Data.fromJson(Map json) {
@@ -86,6 +92,7 @@ class Data {
isHighPriority = json['isHighPriority'];
assetName = json['assetName'];
sessionType = json['sessionType'];
+ requestType = json['requestType'];
numberOfSites = json['numberOfSites'];
numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber'];
@@ -93,6 +100,8 @@ class Data {
requestNo = json['requestNo'];
rejectReason = json['rejectReason'];
transactionNo = json['transactionNo'];
+ poInternal = json['poInternal'];
+ poExternal = json['poExternal'];
nameOfType = json['nameOfType'];
}
diff --git a/lib/models/user.dart b/lib/models/user.dart
index 5eac8486..17da87c9 100644
--- a/lib/models/user.dart
+++ b/lib/models/user.dart
@@ -12,6 +12,7 @@ class User {
List? departmentName;
String? message;
String? username;
+ String? employeeId;
String? userID;
String? email;
String? password;
@@ -53,6 +54,7 @@ class User {
this.departmentName,
this.message,
this.username,
+ this.employeeId,
this.userID,
this.email,
this.password,
@@ -108,10 +110,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;
}
@@ -148,6 +153,7 @@ class User {
map['message'] = message;
map['username'] = username;
map['userID'] = userID;
+ map['employeeId'] = employeeId;
map['email'] = email;
map['password'] = password;
map['token'] = token;
@@ -209,6 +215,7 @@ class User {
message = json['message'];
username = json['username'];
userID = json['userID'];
+ employeeId = json['employeeId'];
email = json['email'];
password = json['password'];
token = json['token'];
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..0cfb122e
--- /dev/null
+++ b/lib/modules/asset_delivery_module/helper_function.dart
@@ -0,0 +1,73 @@
+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, bool viewOnly = false, 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,
+ viewOnly: viewOnly,
+ 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/asset_delivery_data_model.dart b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart
new file mode 100644
index 00000000..15ece8ca
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart
@@ -0,0 +1,386 @@
+import 'package:test_sa/models/lookup.dart';
+
+class AssetDeliveryDataModel {
+ int? id;
+ bool? isHMG;
+ int? operatingUnitId;
+ String? operatingUnit;
+ String? clientName;
+ int? poNumberId;
+ int? poNumber;
+ SiteModel? site;
+ Lookup? paymentTerm;
+ num? paymentTermAmount;
+ num? deliveryAmount;
+ num? total;
+ num? totalInvoice;
+ String? edd;
+ double? warrentyPeriod;
+
+ AssetDeliveryInternalMaster? assetDeliveryInternalMaster;
+ PurchaseOrderMaster? purchaseOrderMaster;
+ List? assetDeliveryExternalDetails;
+ List? assetDeliveryExternalDeliveries;
+
+ AssetDeliveryDataModel();
+
+ AssetDeliveryDataModel.fromJson(Map json) {
+ id = json['id'];
+ isHMG = json['isHMG'];
+ operatingUnitId = json['operatingUnitId'];
+ clientName = json['clientName'];
+ operatingUnit = json['operatingUnit'];
+ poNumberId = json['poNumberId'];
+ poNumber = json['poNumber'];
+ total = json['total'];
+ totalInvoice = json['totalInvoice'];
+ edd = json['edd'];
+ deliveryAmount = json['deliveryAmount'];
+ site = json['site'] != null
+ ? SiteModel.fromJson(json['site'])
+ : null;
+ paymentTerm = json['paymentTerm'] != null
+ ? Lookup.fromJson(json['paymentTerm'])
+ : null;
+ paymentTermAmount = json['paymentTermAmount'];
+ warrentyPeriod = json['warrentyPeriod'];
+
+ assetDeliveryInternalMaster = json['assetDeliveryInternalMaster'] != null
+ ? AssetDeliveryInternalMaster.fromJson(json['assetDeliveryInternalMaster'])
+ : null;
+ purchaseOrderMaster = json['purchaseOrderMaster'] != null
+ ? PurchaseOrderMaster.fromJson(json['purchaseOrderMaster'])
+ : null;
+
+ if (json['assetDeliveryExternalDetails'] != null) {
+ assetDeliveryExternalDetails = [];
+ json['assetDeliveryExternalDetails'].forEach((v) {
+ assetDeliveryExternalDetails!.add(AssetDeliveryExternalDetail.fromJson(v));
+ });
+ }
+
+ if (json['assetDeliveryExternalDeliveries'] != null) {
+ assetDeliveryExternalDeliveries = [];
+ json['assetDeliveryExternalDeliveries'].forEach((v) {
+ assetDeliveryExternalDeliveries!.add(AssetDeliveryTableModel.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final data = {};
+
+ data['id'] = id;
+ data['isHMG'] = isHMG;
+ data['operatingUnitId'] = operatingUnitId;
+ data['operatingUnit'] = operatingUnit;
+ data['clientName'] = clientName;
+ data['poNumberId'] = poNumberId;
+ data['poNumber'] = poNumber;
+ data['total'] = total;
+ data['edd'] = edd;
+ data['totalInvoice'] = totalInvoice;
+ data['deliveryAmount'] = deliveryAmount;
+ data['site'] = site;
+ data['paymentTermAmount'] = paymentTermAmount;
+ data['warrentyPeriod'] = warrentyPeriod;
+
+ if (paymentTerm != null) data['paymentTerm'] = paymentTerm!.toJson();
+ if (assetDeliveryInternalMaster != null) {
+ data['assetDeliveryInternalMaster'] =
+ assetDeliveryInternalMaster!.toJson();
+ }
+ if (assetDeliveryExternalDetails != null) {
+ data['assetDeliveryExternalDetails'] =
+ assetDeliveryExternalDetails!.map((v) => v.toJson()).toList();
+ }
+ if (assetDeliveryExternalDeliveries != null) {
+ data['assetDeliveryExternalDeliveries'] =
+ assetDeliveryExternalDeliveries!.map((v) => v.toJson()).toList();
+ }
+
+ return data;
+ }
+}
+
+
+class AssetDeliveryInternalMaster {
+ int? id;
+ int? operatingUnitId;
+ String? operatingUnit;
+ int? poNumberId;
+ int? poNumber;
+ String? supplier;
+ String? supplierSite;
+ String? type;
+ String? buyer;
+ num? total;
+ String? currency;
+ String? remark;
+ String? status;
+ String? paymentTerms;
+ double? warrantyPeriod;
+ String? assetDeliveryStatus;
+ String? statusDocument;
+ String? remarkDocument;
+ String? edd;
+
+ AssetDeliveryInternalMaster();
+
+ AssetDeliveryInternalMaster.fromJson(Map json) {
+ id = json['id'];
+ operatingUnitId = json['operatingUnitId'];
+ operatingUnit = json['operatingUnit'];
+ poNumberId = json['poNumberId'];
+ poNumber = json['poNumber'];
+ supplier = json['supplier'];
+ supplierSite = json['supplierSite'];
+ type = json['type'];
+ buyer = json['buyer'];
+ total = json['total'];
+ currency = json['currency'];
+ remark = json['remark'];
+ status = json['status'];
+ paymentTerms = json['paymentTerms'];
+ warrantyPeriod = json['warrantyPeriod'];
+ assetDeliveryStatus = json['assetDeliveryStatus'];
+ statusDocument = json['statusDocument'];
+ remarkDocument = json['remarkDocument'];
+ edd = json['edd'];
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'operatingUnitId': operatingUnitId,
+ 'operatingUnit': operatingUnit,
+ 'poNumberId': poNumberId,
+ 'poNumber': poNumber,
+ 'supplier': supplier,
+ 'supplierSite': supplierSite,
+ 'type': type,
+ 'buyer': buyer,
+ 'total': total,
+ 'currency': currency,
+ 'remark': remark,
+ 'status': status,
+ 'paymentTerms': paymentTerms,
+ 'warrantyPeriod': warrantyPeriod,
+ 'assetDeliveryStatus': assetDeliveryStatus,
+ 'statusDocument': statusDocument,
+ 'remarkDocument': remarkDocument,
+ 'edd': edd,
+ };
+ }
+}
+
+class AssetDeliveryExternalDetail {
+ int? id;
+ AssetDeliveryInternalDetail? assetDeliveryInternalDetail;
+ String? itemNumber;
+ String? lineType;
+ String? unitMeasure;
+ num? qtyOrdered;
+ num? qtyReceived;
+ num? qtyBilled;
+ num? qtyCancelled;
+ num? unitPrice;
+ num? unitPriceWithTax;
+ String? itemDescription;
+
+ AssetDeliveryExternalDetail();
+
+ AssetDeliveryExternalDetail.fromJson(Map json) {
+ id = json['id'];
+ itemNumber = json['itemNumber'];
+ lineType = json['lineType'];
+ unitMeasure = json['unitMeasure'];
+ qtyOrdered = json['qtyOrdered'];
+ qtyReceived = json['qtyReceived'];
+ qtyBilled = json['qtyBilled'];
+ qtyCancelled = json['qtyCancelled'];
+ unitPrice = json['unitPrice'];
+ unitPriceWithTax = json['unitPriceWithTax'];
+ itemDescription = json['itemDescription'];
+
+ assetDeliveryInternalDetail =
+ json['assetDeliveryInternalDetail'] != null
+ ? AssetDeliveryInternalDetail.fromJson(
+ json['assetDeliveryInternalDetail'])
+ : null;
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'itemNumber': itemNumber,
+ 'lineType': lineType,
+ 'unitMeasure': unitMeasure,
+ 'qtyOrdered': qtyOrdered,
+ 'qtyReceived': qtyReceived,
+ 'qtyBilled': qtyBilled,
+ 'qtyCancelled': qtyCancelled,
+ 'unitPrice': unitPrice,
+ 'unitPriceWithTax': unitPriceWithTax,
+ 'itemDescription': itemDescription,
+ 'assetDeliveryInternalDetail':
+ assetDeliveryInternalDetail?.toJson(),
+ };
+ }
+}
+
+class AssetDeliveryInternalDetail {
+ int? id;
+ int? lineId;
+ String? itemNumber;
+ String? itemDescription;
+ String? unitMeasure;
+ num? qtyOrdered;
+ num? qtyReceived;
+ num? qtyBilled;
+ num? qtyCancelled;
+ num? unitPrice;
+ num? unitPriceWithTax;
+ Lookup? itemCategory;
+ num? totalAssets;
+ num? childPerAsset;
+
+ AssetDeliveryInternalDetail();
+
+ AssetDeliveryInternalDetail.fromJson(Map json) {
+ id = json['id'];
+ lineId = json['lineId'];
+ itemNumber = json['itemNumber'];
+ itemDescription = json['itemDescription'];
+ unitMeasure = json['unitMeasure'];
+ qtyOrdered = json['qtyOrdered'];
+ qtyReceived = json['qtyReceived'];
+ qtyBilled = json['qtyBilled'];
+ qtyCancelled = json['qtyCancelled'];
+ unitPrice = json['unitPrice'];
+ unitPriceWithTax = json['unitPriceWithTax'];
+ itemCategory = json['itemCategory'] != null
+ ? Lookup.fromJson(json['itemCategory'])
+ : null;
+ totalAssets = json['totalAssets'];
+ childPerAsset = json['childPerAsset'];
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'lineId': lineId,
+ 'itemNumber': itemNumber,
+ 'itemDescription': itemDescription,
+ 'unitMeasure': unitMeasure,
+ 'qtyOrdered': qtyOrdered,
+ 'qtyReceived': qtyReceived,
+ 'qtyBilled': qtyBilled,
+ 'qtyCancelled': qtyCancelled,
+ 'unitPrice': unitPrice,
+ 'unitPriceWithTax': unitPriceWithTax,
+ 'itemCategory': itemCategory,
+ 'totalAssets': totalAssets,
+ 'childPerAsset': childPerAsset,
+ };
+ }
+}
+class AssetDeliveryTableModel {
+ int? id;
+ Lookup? status;
+ String? number;
+ num? deliveryAmount;
+ num? invoiceAmount;
+ bool? isContainsTechnicalInspection;
+
+ AssetDeliveryTableModel();
+
+ AssetDeliveryTableModel.fromJson(Map json) {
+ id = json['id'];
+ number = json['number'];
+ deliveryAmount = json['deliveryAmount'];
+ invoiceAmount = json['invoiceAmount'];
+ isContainsTechnicalInspection = json['isContainsTechnicalInspection'];
+
+ status = json['status'] != null
+ ? Lookup.fromJson(json['status'])
+ : null;
+
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'number': number,
+ 'deliveryAmount': deliveryAmount,
+ 'invoiceAmount': invoiceAmount,
+ 'isContainsTechnicalInspection': isContainsTechnicalInspection,
+ 'status': status?.toJson(),
+ };
+ }
+}
+
+class PurchaseOrderMaster {
+ int? id;
+ num? poNumber;
+ int? siteId;
+ String? siteName;
+ num? amount;
+ String? remarks;
+ String? statuss;
+ List? assetDeliveryPurchaseOrderDetails;
+
+ PurchaseOrderMaster({
+ this.id,
+ this.poNumber,
+ this.siteId,
+ this.siteName,
+ this.amount,
+ this.remarks,
+ this.statuss,
+ this.assetDeliveryPurchaseOrderDetails,
+ });
+
+ PurchaseOrderMaster.fromJson(Map json) {
+ id = json['id'];
+ poNumber = json['poNumber'];
+ siteId = json['siteId'];
+ siteName = json['siteName'];
+ amount = json['amount'];
+ remarks = json['remarks'];
+ statuss = json['statuss'];
+
+ if (json['assetDeliveryPurchaseOrderDetails'] != null &&
+ json['assetDeliveryPurchaseOrderDetails'] is List) {
+ assetDeliveryPurchaseOrderDetails =
+ (json['assetDeliveryPurchaseOrderDetails'] as List)
+ .map((e) => PurchaseOrderDetails.fromJson(e))
+ .toList();
+ } else {
+ assetDeliveryPurchaseOrderDetails = null;
+ }
+ }
+}
+
+class SiteModel{
+ int? id;
+ String? siteName;
+
+ SiteModel({
+ this.id,
+ this.siteName,
+ });
+
+ SiteModel.fromJson(Map json) {
+ id = json['id'];
+ siteName = json['siteName'];
+ }
+}
+///Check this model if required and whats the parm
+class PurchaseOrderDetails {
+ // No fields provided in your JSON – placeholder
+ PurchaseOrderDetails();
+
+ PurchaseOrderDetails.fromJson(Map json);
+}
+
diff --git a/lib/modules/asset_delivery_module/models/cost_center_model.dart b/lib/modules/asset_delivery_module/models/cost_center_model.dart
new file mode 100644
index 00000000..0cacd34a
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/cost_center_model.dart
@@ -0,0 +1,57 @@
+import 'package:test_sa/models/lookup.dart';
+
+class CostCenterModel {
+ int? id;
+ int? assetDeliveryExternalDetailId;
+ Lookup? costCenter;
+ String? acceptedBy;
+ String? costCenterName;
+ DateTime? acceptanceDate;
+ String? acceptedByEmail;
+ String? acceptedBySignature;
+ double? quantity;
+
+ CostCenterModel({
+ this.id,
+ this.assetDeliveryExternalDetailId,
+ this.costCenter,
+ this.acceptedBy,
+ this.costCenterName,
+ this.acceptanceDate,
+ this.acceptedByEmail,
+ this.acceptedBySignature,
+ this.quantity,
+ });
+
+ CostCenterModel.fromJson(Map json) {
+ costCenterName = json['costCenter'] ?? json['costCenterName'];
+ acceptanceDate = json['acceptanceDate'] != null ? DateTime.tryParse(json['acceptanceDate']) : null;
+ acceptedBySignature = json['acceptedBySignature'];
+ acceptedByEmail = json['acceptedByEmail'];
+ quantity = json['qty'] ?? json['costCenterQty'];
+ acceptedBy = json['acceptedBy'];
+ costCenter = json['costCenter'] != null ? Lookup(name: json['costCenter']) : null;
+ id = json['id'] ?? json['costCenterId'];
+ assetDeliveryExternalDetailId = json['assetDeliveryExternalDetailId'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+
+ data['id'] = id ?? 0;
+ data['qty'] = quantity;
+ data['costCenter'] = costCenterName;
+ return data;
+ }
+
+ Map toEndUserAcceptanceFormJson() {
+ final Map data = {};
+ data['assetDeliveryExternalDeliveryId'] = assetDeliveryExternalDetailId;
+ data['costCenterName'] = costCenterName;
+ data['acceptedBy'] = acceptedBy;
+ data['acceptanceDate'] = acceptanceDate?.toIso8601String();
+ data['acceptedByEmail'] = acceptedByEmail;
+ data['acceptedBySignature'] = acceptedBySignature;
+ 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
new file mode 100644
index 00000000..4d73b496
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/delivery_inspection_form_model.dart
@@ -0,0 +1,57 @@
+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;
+ String? deliveryInspectionApprovedBy;
+
+ DeliveryInspectionFormModel({
+ this.assetDeliveryExternalDeliveryId,
+ this.deliveryInspectionInspectedBy,
+ this.inspectedByModel,
+ this.approvedByModel,
+ this.thirdApprovalModel,
+ this.deliveryInspectionInspectedDateFrom,
+ this.deliveryInspectionInspectedDateTo,
+ this.totalTime,
+ this.deliveryInspectionApprovedBy,
+ });
+
+ DeliveryInspectionFormModel.fromJson(Map json) {
+ assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId'];
+ deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy'];
+ 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,
+ 'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(),
+ 'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(),
+ 'totalTime': totalTime,
+ '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/delivery_line_model.dart b/lib/modules/asset_delivery_module/models/delivery_line_model.dart
new file mode 100644
index 00000000..d715c8c1
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/delivery_line_model.dart
@@ -0,0 +1,61 @@
+class DeliveryLineModel {
+ int? id;
+ int? assetDeliveryInternalDetailId;
+ String? itemNumber;
+ String? itemDescription;
+ num? qty;
+ num? remainingQty;
+ num? usingQtyInThisDelivery;
+ num? unitPrice;
+ num? total;
+ String? unitOfMeasure;
+ String? lineType;
+ String? itemCategory;
+
+ DeliveryLineModel({
+ this.id,
+ this.assetDeliveryInternalDetailId,
+ this.itemNumber,
+ this.itemDescription,
+ this.qty,
+ this.remainingQty,
+ this.usingQtyInThisDelivery,
+ this.unitPrice,
+ this.total,
+ this.unitOfMeasure,
+ this.lineType,
+ this.itemCategory,
+ });
+
+ DeliveryLineModel.fromJson(Map json) {
+ id = json['id'];
+ assetDeliveryInternalDetailId = json['assetDeliveryInternalDetailId'];
+ itemNumber = json['itemNumber'];
+ itemDescription = json['itemDescription'];
+ qty = json['qty'];
+ remainingQty = json['remainingQty'];
+ usingQtyInThisDelivery = json['usingQtyInThisDelivery'];
+ unitPrice = json['unitPrice'];
+ total = json['total'];
+ unitOfMeasure = json['unitOfMeasure'];
+ lineType = json['lineType'];
+ itemCategory = json['itemCategory'];
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'assetDeliveryInternalDetailId': assetDeliveryInternalDetailId,
+ 'itemNumber': itemNumber,
+ 'itemDescription': itemDescription,
+ 'qty': qty,
+ 'remainingQty': remainingQty,
+ 'usingQtyInThisDelivery': usingQtyInThisDelivery,
+ 'unitPrice': unitPrice,
+ 'total': total,
+ 'unitOfMeasure': unitOfMeasure,
+ 'lineType': lineType,
+ 'itemCategory': itemCategory,
+ };
+ }
+}
diff --git a/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart b/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart
new file mode 100644
index 00000000..242cf70a
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/end_user_asset_details_model.dart
@@ -0,0 +1,71 @@
+import 'package:test_sa/models/lookup.dart';
+
+class EndUserAssetDetailsModel {
+ int? id;
+ int? typeId;
+ int? assetDeliveryExternalDeliveryId;
+ String? type;
+ String? itemNumber;
+ String? costCenterName;
+ Lookup? status;
+ Lookup? rejectionReason;
+ String? description;
+ double? receivedQty;
+ num? rejectedQty;
+ String? assetNumber;
+ String? serialNo;
+ String? assetType;
+ String? replacedAssetNo;
+
+ EndUserAssetDetailsModel(
+ {this.costCenterName,
+ this.rejectedQty,
+ this.description,
+ this.id,
+ this.typeId,
+ this.status,
+ this.rejectionReason,
+ this.assetType,
+ this.assetNumber,
+ this.serialNo,
+ this.itemNumber,
+ this.type,
+ this.receivedQty,
+ this.replacedAssetNo,
+ this.assetDeliveryExternalDeliveryId});
+
+ EndUserAssetDetailsModel.fromJson(Map json) {
+ id = json['id'];
+ typeId = json['typeId'];
+ type = json['type'];
+ itemNumber = json['itemNumber'];
+ status = json['status'] != null ? Lookup.fromJson(json['status']) : null;
+ rejectionReason = json['rejectReason'] != null ? Lookup.fromJson(json['rejectReason']) : null;
+ description = json['description'];
+ receivedQty = json['receivedQty'];
+ rejectedQty = json['rejectedQty'];
+ assetNumber = json['assetNumber'];
+ serialNo = json['serialNo'];
+ assetType = json['assetType'];
+ replacedAssetNo = json['replacedAssetNo'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['assetDeliveryExternalDeliveryId'] = assetDeliveryExternalDeliveryId;
+ data['costCenterName'] = costCenterName;
+ data['typeId'] = typeId;
+ data['type'] = type;
+ data['itemNumber'] = itemNumber;
+ data['statusId'] = status?.id;
+ // data['status'] = status;
+ // data['rejectionReason'] = rejectionReason;
+ data['rejectReasonId'] = rejectionReason?.id;
+ data['description'] = description;
+ data['receivedQty'] = receivedQty;
+ data['rejectedQty'] = rejectedQty;
+
+ return data;
+ }
+}
diff --git a/lib/modules/asset_delivery_module/models/history_model.dart b/lib/modules/asset_delivery_module/models/history_model.dart
new file mode 100644
index 00000000..67fc4e11
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/history_model.dart
@@ -0,0 +1,34 @@
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/models/new_models/work_order_detail_model.dart';
+
+class AssetDeliveryHistoryModel {
+ WorkOrderAssignedEmployee? user;
+ Lookup? status;
+ DateTime? createdDate;
+ String ?timeDifference;
+
+ AssetDeliveryHistoryModel({
+ this.user,
+ this.status,
+ this.createdDate,
+ this.timeDifference,
+ });
+
+ AssetDeliveryHistoryModel.fromJson(Map json) {
+ user = json['user'] != null ? WorkOrderAssignedEmployee.fromJson(json['user']) : null;
+ status = json['status'] != null ? Lookup.fromJson(json['status']) : null;
+ createdDate = json['createdDate'] != null ? DateTime.tryParse(json['createdDate']) : null;
+ timeDifference = '';
+ }
+
+ Map toJson() {
+ final Map data = {};
+ if (user != null) {
+ data['user'] = user!.toJson();
+ }
+ if (status != null) {
+ data['status'] = status!.toJson();
+ }
+ return data;
+ }
+}
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/models/oracle_user_model.dart b/lib/modules/asset_delivery_module/models/oracle_user_model.dart
new file mode 100644
index 00000000..90ed9ee3
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/oracle_user_model.dart
@@ -0,0 +1,26 @@
+class OracleUserModel {
+ String? employeeNumber;
+ String? fullName;
+ String? job;
+ String? employeeMobileNumber;
+ String? employeeExtensionNumber;
+ String? employeeEmail;
+
+ OracleUserModel({
+ this.employeeNumber,
+ this.fullName,
+ this.job,
+ this.employeeMobileNumber,
+ this.employeeExtensionNumber,
+ this.employeeEmail,
+ });
+
+ OracleUserModel.fromJson(Map json) {
+ employeeNumber = json['employeeNumber'];
+ fullName = json['fullName'];
+ job = json['job'];
+ employeeMobileNumber = json['employeeMobileNumber'];
+ employeeExtensionNumber = json['employeeExtensionNumber'];
+ employeeEmail = json['employeeEmail'];
+ }
+}
diff --git a/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart
new file mode 100644
index 00000000..7404b585
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/technical_inpection_asset_model.dart
@@ -0,0 +1,61 @@
+class TechnicalInspectionAssetBasicInfoModel {
+ int? id;
+ String? assetNumber;
+ String? assetType;
+ String? assetOrigin;
+ String? assetName;
+ String? model;
+ String? manufacturer;
+ String? site;
+ String? building;
+ String? floor;
+ String? department;
+ String? room;
+
+ TechnicalInspectionAssetBasicInfoModel({
+ this.id,
+ this.assetNumber,
+ this.assetType,
+ this.assetOrigin,
+ this.assetName,
+ this.model,
+ this.manufacturer,
+ this.site,
+ this.building,
+ this.floor,
+ this.department,
+ this.room,
+ });
+
+ TechnicalInspectionAssetBasicInfoModel.fromJson(Map json) {
+ id = json['id'];
+ assetNumber = json['assetNumber'];
+ assetType = json['assetType'];
+ assetOrigin = json['assetOrigin'];
+ assetName = json['assetName'];
+ model = json['model'];
+ manufacturer = json['manufacturer'];
+ site = json['site'];
+ building = json['building'];
+ floor = json['floor'];
+ department = json['department'];
+ room = json['room'];
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'assetNumber': assetNumber,
+ 'assetType': assetType,
+ 'assetOrigin': assetOrigin,
+ 'assetName': assetName,
+ 'model': model,
+ 'manufacturer': manufacturer,
+ 'site': site,
+ 'building': building,
+ 'floor': floor,
+ 'department': department,
+ 'room': room,
+ };
+ }
+}
diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart
new file mode 100644
index 00000000..fafcc277
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart
@@ -0,0 +1,215 @@
+import 'dart:developer';
+
+import 'package:test_sa/models/device/supplier.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/models/new_models/building.dart';
+import 'package:test_sa/models/new_models/floor.dart';
+import 'package:test_sa/models/new_models/room_model.dart';
+import 'package:test_sa/models/new_models/site.dart';
+
+import '../../../models/device/model_definition.dart';
+import '../../../models/new_models/department.dart';
+
+class TechnicalInspectionAssetModel {
+ num? id;
+ num? tableItemId;
+ num? lineId;
+ num? assetDeliveryInternalDetailAssetId;
+ num? assetDeliveryInternalDetailAssetChildId;
+ num? costCenterId;
+ String? assetNumber;
+ String? status;
+ Lookup? assetOrigin;
+ Lookup? replacedAsset;
+ AssetModelDefination? modelDefinition;
+ Supplier? supplier;
+ Lookup? assetType; // Now nullable
+ Site? site; // Now nullable
+ Building? building; // Now nullable
+ Floor? floor; // Now nullable
+ Department? department; // Now nullable
+ Rooms? room;
+ String? serialNo;
+ String? systemId;
+ DateTime? installationDate;
+ List? childAssetList;
+ bool? flagphysicalInspection;
+ bool? flagFunctionPerformance;
+ bool? flagGroundingResistance;
+ bool? flagChassiss;
+ bool? flagLeadsLeakage;
+ bool? flagAlert;
+
+ TechnicalInspectionAssetModel({
+ this.id,
+ this.assetDeliveryInternalDetailAssetId,
+ this.assetDeliveryInternalDetailAssetChildId,
+ this.tableItemId,
+ this.status,
+ this.lineId,
+ this.costCenterId,
+ this.assetNumber,
+ this.assetOrigin,
+ this.assetType,
+ this.replacedAsset,
+ this.modelDefinition,
+ this.supplier,
+ this.site,
+ this.building,
+ this.floor,
+ this.department,
+ this.room,
+ this.serialNo,
+ this.systemId,
+ this.installationDate,
+ this.childAssetList,
+ this.flagphysicalInspection,
+ this.flagFunctionPerformance,
+ this.flagGroundingResistance,
+ this.flagChassiss,
+ this.flagLeadsLeakage,
+ this.flagAlert,
+ });
+
+ TechnicalInspectionAssetModel.fromJson(Map json) {
+ id = json['id'];
+ assetDeliveryInternalDetailAssetId = json['assetDeliveryInternalDetailAssetId'];
+ assetDeliveryInternalDetailAssetChildId = json['assetDeliveryInternalDetailAssetChildId'];
+ assetNumber = json['assetNumber'];
+ assetOrigin = json['assetOrigin'] != null ? Lookup.fromJson(json['assetOrigin']) : null;
+ replacedAsset = json['replacedAsset'] != null ? Lookup.fromJson(json['replacedAsset']) : null;
+ modelDefinition = json['modelDefinition'] != null ? AssetModelDefination.fromJson(json['modelDefinition']) : null;
+ supplier = json['supplier'] != null ? Supplier.fromJson(json['supplier']) : null;
+ assetType = json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null;
+ site = json['site'] != null ? Site.fromJson(json['site']) : null;
+ building = json['building'] != null ? Building.fromJson(json['building']) : null;
+ floor = json['floor'] != null ? Floor.fromJson(json['floor']) : null;
+ department = json['department'] != null ? Department.fromJson(json['department']) : null;
+ room = json['room'] != null ? Rooms.fromJson(json['room']) : null;
+ serialNo = json['serialNo'];
+ systemId = json['systemId'];
+ installationDate = json['installationDate'] != null ? DateTime.tryParse(json['installationDate']) : null;
+ childAssetList =
+ json['assetDeliveryInternalDetailAssetChild'] != null ? (json['assetDeliveryInternalDetailAssetChild'] as List).map((e) => TechnicalInspectionAssetModel.fromJson(e)).toList() : [];
+ //Need to keep one parm from backend
+ // childAssetList = json['assetDeliveryExternalDeliveryLineTechnicalInspectionItemChild'] != null
+ // ? (json['assetDeliveryExternalDeliveryLineTechnicalInspectionItemChild'] as List).map((e) => TechnicalInspectionAssetModel.fromJson(e)).toList()
+ // : [];
+ flagphysicalInspection = json['flagphysicalInspection'];
+ flagFunctionPerformance = json['flagFunctionPerformance'];
+ flagGroundingResistance = json['flagGroundingResistance'];
+ flagChassiss = json['flagChassiss'];
+ flagLeadsLeakage = json['flagLeadsLeakage'];
+ flagAlert = json['flagAlert'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['assetDeliveryInternalDetailAssetId'] = assetDeliveryInternalDetailAssetId;
+ data['assetDeliveryExternalDeliveryId'] = tableItemId;
+ data['assetDeliveryExternalDetailId'] = lineId;
+ data['costCenterId'] = costCenterId;
+ data['assetNumber'] = assetNumber;
+ data['assetOriginId'] = assetOrigin?.id;
+ data['assetTypeId'] = assetType?.id;
+ data['replacedAssetId'] = replacedAsset?.id;
+ data['modelDefinitionId'] = modelDefinition?.modelDefinitionId;
+ data['supplierId'] = supplier?.id;
+ data['siteId'] = site?.id;
+ data['buildingId'] = building?.id;
+ data['floorId'] = floor?.id;
+ data['departmentId'] = department?.id;
+ data['roomId'] = room?.id;
+ data['serialNo'] = serialNo;
+ data['systemId'] = systemId;
+ data['installationDate'] = installationDate?.toIso8601String();
+ data['assetDeliveryInternalDetailAssetChild'] = childAssetList?.map((e) => e.toChildJson()).toList();
+ data['flagphysicalInspection'] = flagphysicalInspection;
+ data['flagFunctionPerformance'] = flagFunctionPerformance;
+ data['flagGroundingResistance'] = flagGroundingResistance;
+ data['flagChassiss'] = flagChassiss;
+ data['flagLeadsLeakage'] = flagLeadsLeakage;
+ data['flagAlert'] = flagAlert;
+ return data;
+ }
+
+ Map toChildJson() {
+ final Map data = {};
+ data['id'] = id ?? 0;
+ data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId;
+ data['assetNumber'] = assetNumber;
+ data['assetOriginId'] = assetOrigin?.id;
+ data['assetTypeId'] = assetType?.id;
+ data['replacedAssetId'] = replacedAsset?.id;
+ data['modelDefinitionId'] = modelDefinition?.modelDefinitionId;
+ data['supplierId'] = supplier?.id;
+ data['siteId'] = site?.id;
+ data['buildingId'] = building?.id;
+ data['floorId'] = floor?.id;
+ data['departmentId'] = department?.id;
+ data['roomId'] = room?.id;
+ data['serialNo'] = serialNo;
+ data['systemId'] = systemId;
+ data['installationDate'] = installationDate?.toIso8601String();
+ data['flagphysicalInspection'] = flagphysicalInspection;
+ data['flagFunctionPerformance'] = flagFunctionPerformance;
+ data['flagGroundingResistance'] = flagGroundingResistance;
+ data['flagChassiss'] = flagChassiss;
+ data['flagLeadsLeakage'] = flagLeadsLeakage;
+ data['flagAlert'] = flagAlert;
+ return data;
+ }
+}
+
+class InspectionChecklistItem {
+ String? title;
+ String? value;
+ String? status; // "PASS" or "FAIL"
+
+ InspectionChecklistItem({this.title, this.status, this.value});
+
+ InspectionChecklistItem.fromJson(Map json) {
+ title = json['title'];
+ value = json['value'];
+ status = json['status'];
+ }
+
+ Map toJson() {
+ return {
+ 'title': title,
+ 'value': value,
+ 'status': status,
+ };
+ }
+}
+
+class AssetModelDefination {
+ int? modelDefinitionId;
+ String? assetName;
+ String? model;
+ String? manufacturer;
+
+ AssetModelDefination({
+ this.modelDefinitionId,
+ this.assetName,
+ this.model,
+ this.manufacturer,
+ });
+
+ AssetModelDefination.fromJson(Map json) {
+ modelDefinitionId = json['modelDefinitionId'];
+ assetName = json['assetName'];
+ model = json['model'];
+ manufacturer = json['manufacturer'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['modelDefinitionId'] = modelDefinitionId;
+ data['assetName'] = assetName;
+ data['model'] = model;
+ data['manufacturer'] = manufacturer;
+ return data;
+ }
+}
diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart
new file mode 100644
index 00000000..cbde7191
--- /dev/null
+++ b/lib/modules/asset_delivery_module/models/technical_inspection_form_model.dart
@@ -0,0 +1,53 @@
+import 'dart:developer';
+
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
+
+class TechnicalInspectionFormModel {
+ Lookup? powerSupplyType;
+ num? powerReading;
+ num? maxCurrent;
+ num? voltage;
+ num? frequency;
+ List? costCenters;
+ int? tableItemId;
+ int? lineId;
+
+ TechnicalInspectionFormModel({
+ this.powerSupplyType,
+ this.powerReading,
+ this.maxCurrent,
+ this.voltage,
+ this.frequency,
+ this.costCenters,
+ this.lineId,
+ this.tableItemId,
+ });
+
+ TechnicalInspectionFormModel.fromJson(Map json) {
+ powerSupplyType = json["powerSupplyType"] == null ? null : Lookup.fromJson(json["powerSupplyType"]);
+ powerReading = json['powerReading'];
+ maxCurrent = json['maxCurrent'];
+ voltage = json['voltage'];
+ frequency = json['frequency'];
+ if (json['costCenters'] != null) {
+ costCenters = [];
+ json['costCenters'].forEach((v) {
+ costCenters!.add(CostCenterModel.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['powerSupplyTypeId'] = powerSupplyType?.id;
+ data['assetDeliveryExternalDeliveryId'] = tableItemId;
+ data['assetDeliveryExternalDetailId'] = lineId;
+ data['powerReading'] = powerReading;
+ data['maxCurrent'] = maxCurrent;
+ data['voltage'] = voltage;
+ data['frequency'] = frequency;
+ // data['costCenters'] = costCenters != null ? costCenters!.map((v) => v.toJson()).toList() : [];
+ return data;
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart
new file mode 100644
index 00000000..ff02233c
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_item_view.dart
@@ -0,0 +1,90 @@
+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/asset_delivery_module/pages/asset_delivery_page.dart';
+import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class AssetDeliveryItemView extends StatelessWidget {
+ final Data? requestData;
+ final RequestsDetails? requestDetails;
+ final bool showShadow;
+
+ const AssetDeliveryItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ if (requestData != null) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 8.height,
+ (requestData?.typeTransaction ?? 'Asset Delivery').heading5(context),
+ infoWidget(label: 'PO Internal'.addTranslation, value: requestData?.poInternal ?? '-', context: context),
+ infoWidget(label: 'PO External'.addTranslation, value: requestData?.poExternal ?? '-', context: context),
+ // infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', 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.of(context).push(MaterialPageRoute(
+ builder: (_) => AssetDeliveryPage(
+ requestId: requestData!.id!,
+ poInternal: requestData?.poInternal,
+ poExternal: requestData?.poExternal,
+ )));
+ });
+ }
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 8.height,
+ (requestDetails?.nameOfType ?? 'Asset Delivery').heading5(context),
+ infoWidget(label: 'PO Internal'.addTranslation, value: requestDetails?.poInternal ?? '-', context: context),
+ infoWidget(label: 'PO External'.addTranslation, value: requestDetails?.poExternal ?? '-', 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.of(context).push(MaterialPageRoute(
+ builder: (_) => AssetDeliveryPage(
+ requestId: requestDetails!.id!,
+ poInternal: requestDetails?.poInternal,
+ poExternal: requestDetails?.poExternal,
+ )));
+ });
+ }
+
+ 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/asset_delivery_module/pages/asset_delivery_line_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart
new file mode 100644
index 00000000..5337f457
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart
@@ -0,0 +1,86 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.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/models/delivery_line_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+
+class AssetDeliveryLineCard extends StatelessWidget {
+ DeliveryLineModel deliveryLineModel;
+ bool isViewOnly;
+ VoidCallback? editPress;
+ bool isTechnical;
+
+ AssetDeliveryLineCard({
+ super.key,
+ required this.isViewOnly,
+ required this.deliveryLineModel,
+ this.isTechnical = false,
+ this.editPress,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ //need to check this @waseem.
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ 'Item Category: ${deliveryLineModel.itemCategory ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset().onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ Text(
+ 'Item No: ${deliveryLineModel.itemNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Item Description: ${deliveryLineModel.itemDescription ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Quantity: ${deliveryLineModel.qty ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+
+ if(!isTechnical)...[
+ Text(
+ 'Remaining Quantity: ${deliveryLineModel.remainingQty ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Quantity of this Delivery: ${deliveryLineModel.usingQtyInThisDelivery ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+
+ Text(
+ 'Measure Unit: ${deliveryLineModel.unitOfMeasure ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Unit price: ${deliveryLineModel.unitPrice ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Line Type: ${deliveryLineModel.lineType ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Total: ${deliveryLineModel.total ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart
new file mode 100644
index 00000000..a4ce0983
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_page.dart
@@ -0,0 +1,364 @@
+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/asset_delivery_module/models/asset_delivery_data_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/change_status_bottomsheet.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/history_log_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.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/default_app_bar.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+
+class AssetDeliveryPage extends StatefulWidget {
+ final int? requestId;
+ final String? poInternal;
+ final String? poExternal;
+
+ const AssetDeliveryPage({
+ Key? key,
+ this.requestId,
+ this.poInternal,
+ this.poExternal,
+ }) : super(key: key);
+
+ @override
+ State createState() => _AssetDeliveryPageState();
+}
+
+class _AssetDeliveryPageState extends State {
+ AssetDeliveryDataModel? dataModel;
+ AssetDeliveryProvider? assetDeliveryProvider;
+ bool loading = false;
+
+ @override
+ void initState() {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getDetailsById();
+ });
+ super.initState();
+ }
+
+ Future getDetailsById() async {
+ setState(() {
+ loading = true;
+ });
+ final futures = [
+ assetDeliveryProvider!.getAssetDeliveryDetailById(requestId: widget.requestId).then((value) => dataModel = value),
+ assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestId),
+ ];
+
+ await Future.wait(futures);
+ setState(() {
+ loading = false;
+ });
+ }
+
+ @override
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ appBar: DefaultAppBar(
+ title: 'Asset Delivery'.addTranslation,
+ onBackPress: () {
+ Navigator.pop(context);
+ },
+ ),
+ body: Consumer(
+ builder: (context, provider, child) {
+ final dataModel = provider.assetDeliveryDataModel;
+ if (loading) {
+ return const CircularProgressIndicator(color: AppColor.primary10).center;
+ }
+ if (dataModel == null) {
+ return const NoDataFound().center;
+ }
+ return SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ requestDetailCard(context),
+ const Divider().defaultStyle(context),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Asset Delivery Table",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ Row(
+ children: [
+ Container(
+ height: 24,
+ width: 24,
+ decoration: const BoxDecoration(
+ shape: BoxShape.circle,
+ color: AppColor.primary10, // or AppColor.blueStatus(context)
+ ),
+ alignment: Alignment.center,
+ child: const Icon(
+ Icons.add,
+ color: Colors.white,
+ size: 16,
+ ),
+ ),
+ 4.width,
+ Text(
+ "Add more",
+ style: AppTextStyles.bodyText.copyWith(
+ color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
+ decoration: TextDecoration.underline,
+ ),
+ ),
+ ],
+ ).onPress(() async {
+ await assetDeliveryProvider?.addNewDelivery(requestId: widget.requestId).then((status) async {
+ if (status) {
+ await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestId);
+ }
+ });
+ }),
+ ],
+ ),
+ 8.height,
+ assetDeliveryTableList(context: context, assetDeliveryProvider: provider),
+ ],
+ ).toShadowContainer(context, borderRadius: 20),
+ );
+ },
+ ),
+ );
+ }
+
+ TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120);
+
+ Widget requestDetailCard(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'PO No. Internal'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ widget.poInternal ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Client Name'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.clientName ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ // Row(
+ // mainAxisSize: MainAxisSize.min,
+ // children: [
+ // Checkbox(
+ // value: dataModel!.isHMG,
+ // activeColor: AppColor.neutral120,
+ // materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ // visualDensity: const VisualDensity(horizontal: -4, vertical: -3),
+ // onChanged: (value) {},
+ // ),
+ // 8.width,
+ // Text(
+ // 'HMG'.addTranslation,
+ // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ // ),
+ // ],
+ // ),
+ 8.height,
+ if (dataModel?.isHMG == true) ...[
+ Text(
+ 'Operation Units'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.operatingUnit ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ] else ...[
+ Text(
+ 'Site'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.site?.siteName ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ],
+ 8.height,
+ Text(
+ 'PO No.'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ //Need to verify this with backend ...
+ // widget.poInternal?? '-',
+ Text(
+ dataModel?.isHMG == true
+ ? dataModel?.poNumber != null
+ ? dataModel!.poNumber.toString()
+ : '-'
+ : dataModel?.poNumber != null
+ ? dataModel!.poNumber.toString()
+ : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Warranty Period'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.warrentyPeriod != null ? dataModel!.warrentyPeriod.toString() : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Payment Term'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.paymentTerm != null ? dataModel!.paymentTerm!.name.toString() : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+
+ Text(
+ 'Payment Terms Amount'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.paymentTermAmount != null ? dataModel!.paymentTermAmount.toString() : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ //Removed as request by Ahmed backend...
+ // Text(
+ // 'EDD (Estimated Delivery Date)'.addTranslation,
+ // style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ // ),
+ // 8.height,
+ // Text(
+ // dataModel?.edd != null ? dataModel!.edd!.toAssetDetailsFormat : '-',
+ // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ // ),
+ // 8.height,
+ Text(
+ 'Total'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.total != null ? dataModel!.total.toString() : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Total Invoice'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ dataModel?.totalInvoice != null ? dataModel!.totalInvoice.toString() : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ],
+ );
+ }
+
+ Widget assetDeliveryTableList({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider}) {
+ List assetDeliveryTableList = assetDeliveryProvider.assetDeliveryTableList;
+ return assetDeliveryProvider.isDeliveryTableListLoading
+ ? SizedBox(height: 200.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center)
+ : assetDeliveryTableList.isEmpty
+ ? const NoDataFound().center
+ : ListView.separated(
+ itemCount: assetDeliveryTableList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ AssetDeliveryTableModel model = assetDeliveryTableList[itemIndex];
+ return AssetDeliveryTableCard(
+ deliveryTableModel: model,
+ onCardTap: () {
+ //status new
+ if (model.status?.value == 1) {
+ AssetDeliveryBottomSheet.changeStatusBottomSheet(
+ context: context,
+ cancelStatusTap: () async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider.changeDeliveryStatusToCancel(itemId: model.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider.getAssetDeliveryTableListById(requestId: widget.requestId);
+ }
+ });
+ },
+ statusChangeTap: () async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider.changeDeliveryStatus(itemId: model.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider.getAssetDeliveryTableListById(requestId: widget.requestId);
+ }
+ });
+ });
+ } else {
+ // Navigator.of(context).push(MaterialPageRoute(
+ // builder: (_) =>
+ // DeliveryInspectionFormView(
+ // deliveryTableModel: model,
+ // requestModel: dataModel,
+ // ),
+ // ));
+ Navigator.of(context).push(MaterialPageRoute(
+ builder: (_) => AssetDeliveryStageTabPage(
+ title: 'Delivery Inspection'.addTranslation,
+ detailWidget: DeliveryInspectionFormView(
+ deliveryTableModel: model,
+ requestModel: dataModel,
+ ),
+ tableId: model.id,
+ ),
+ ));
+ }
+ },
+ onViewHistoryTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => AssetDeliveryHistoryLogView(
+ tableItemId: model.id,
+ )));
+ },
+ );
+ },
+ );
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart
new file mode 100644
index 00000000..959beffc
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart
@@ -0,0 +1,90 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/enum_extensions.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/asset_delivery_module/pages/history_log_view.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+
+class AssetDeliveryStageTabPage extends StatefulWidget {
+ String title;
+ Widget detailWidget;
+ int? tableId;
+
+ AssetDeliveryStageTabPage({
+ Key? key,
+ required this.title,
+ required this.detailWidget,
+ this.tableId,
+ }) : super(key: key);
+
+ @override
+ _AssetDeliveryStageTabPageState createState() {
+ return _AssetDeliveryStageTabPageState();
+ }
+}
+
+class _AssetDeliveryStageTabPageState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ appBar: DefaultAppBar(
+ title: widget.title,
+ ),
+ body: DefaultTabController(
+ length: 2,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight),
+ decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)),
+ child: TabBar(
+ padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth),
+ labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
+ unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
+ unselectedLabelStyle: AppTextStyles.bodyText,
+ labelStyle: AppTextStyles.bodyText,
+ indicatorPadding: EdgeInsets.zero,
+ indicatorSize: TabBarIndicatorSize.tab,
+ dividerColor: Colors.transparent,
+ indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)),
+ tabs: [
+ Tab(text: context.translation.details, height: 57.toScreenHeight),
+ Tab(text: context.translation.historyLogs, height: 57.toScreenHeight),
+ ],
+ ),
+ ),
+ // 12.height,
+ TabBarView(
+ children: [
+ widget.detailWidget,
+ AssetDeliveryHistoryLogView(
+ tableItemId: widget.tableId,
+ ),
+ ],
+ ).expanded,
+ ],
+ ),
+ ));
+ }
+
+
+ String getPageTitle({AssetDeliveryStageEnum? deliveryStage}) {
+ if (deliveryStage == AssetDeliveryStageEnum.deliveryInspection) {
+ return 'Delivery Inspection'.addTranslation;
+ }
+ if (deliveryStage == AssetDeliveryStageEnum.technicalInspection) {
+ return 'Technical Inspection'.addTranslation;
+ }
+ if (deliveryStage == AssetDeliveryStageEnum.endUserAcceptance) {
+ return 'End-User Acceptance'.addTranslation;
+ } else {
+ return 'Details'.addTranslation;
+ }
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart
new file mode 100644
index 00000000..e7a41d96
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_table_card_view.dart
@@ -0,0 +1,78 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/controllers/providers/api/device_transfer_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/asset_delivery_module/models/asset_delivery_data_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class AssetDeliveryTableCard extends StatelessWidget {
+ AssetDeliveryTableModel deliveryTableModel;
+ VoidCallback onCardTap;
+ VoidCallback onViewHistoryTap;
+
+ AssetDeliveryTableCard({
+ super.key,
+ required this.deliveryTableModel,
+ required this.onCardTap,
+ required this.onViewHistoryTap,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StatusLabel(
+ label: deliveryTableModel.status?.name,
+ textColor: AppColor.neutral50,
+ backgroundColor: AppColor.orange30,
+ ),
+ // Row(
+ // mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // children: [
+ // StatusLabel(
+ // label: deliveryTableModel.status?.name,
+ // textColor: AppColor.neutral50,
+ // backgroundColor: AppColor.orange30,
+ // ),
+ // Row(
+ // children: [
+ // 'history_icon'.toSvgAsset(height: 14, width: 14),
+ // 8.width,
+ // Text(
+ // 'View History'.addTranslation,
+ // style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10),
+ // ),
+ // ],
+ // ).onPress(() {
+ // onViewHistoryTap();
+ // }),
+ // ],
+ // ),
+ 8.height,
+ Text(
+ 'Delivery Number: ${deliveryTableModel.number ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Delivery Amount: ${deliveryTableModel.deliveryAmount ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Invoice Amount: ${deliveryTableModel.invoiceAmount ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Align(
+ alignment: Alignment.centerRight,
+ child: Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14),
+ ),
+ ],
+ ).toShadowContainer(context, borderRadius: 20).onPress(() {
+ onCardTap();
+ });
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/asset_delivery_utils.dart b/lib/modules/asset_delivery_module/pages/asset_delivery_utils.dart
new file mode 100644
index 00000000..ffa4a1b4
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/asset_delivery_utils.dart
@@ -0,0 +1,18 @@
+
+
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+
+class AssetDeliveryUtils{
+ ///This is static list for now if change in future backend provide Api as discuss with backend team
+ static List inspectionChecklist = [
+ InspectionChecklistItem(title: 'Physical Inspection As Per Manufacturer Instructions', value: 'flagphysicalInspection'),
+ InspectionChecklistItem(title: 'Functional Performance As Per Results Of Manufacturer Recommended Check List', value: 'flagFunctionPerformance'),
+ InspectionChecklistItem(title: 'Grounding Resistance: Ω', value: 'flagGroundingResistance'),
+ InspectionChecklistItem(title: 'Chassis Leakage Current: µA', value: 'flagChassiss'),
+ InspectionChecklistItem(title: 'Leads Leakage Current: µA', value: 'flagLeadsLeakage'),
+ InspectionChecklistItem(title: 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form', value: 'flagAlert'),
+ ];
+
+
+
+}
\ No newline at end of file
diff --git a/lib/modules/asset_delivery_module/pages/attachment_view.dart b/lib/modules/asset_delivery_module/pages/attachment_view.dart
new file mode 100644
index 00000000..2f4020e7
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/attachment_view.dart
@@ -0,0 +1,152 @@
+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';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/generic_attachment_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
+import 'package:test_sa/modules/cm_module/cm_request_utils.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_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 {
+ final int? tableItemId;
+ final int? attachmentType;
+ bool viewOnly = false;
+ final List attachmentList;
+
+ AssetDeliveryAttachmentView({
+ super.key,
+ required this.attachmentList,
+ this.viewOnly=false,
+ this.attachmentType,
+ this.tableItemId,
+ });
+
+ @override
+ State createState() => _AssetDeliveryAttachmentViewState();
+}
+
+class _AssetDeliveryAttachmentViewState extends State {
+ List _attachments = [];
+ bool isLoading = false;
+ late AssetDeliveryProvider assetDeliveryProvider;
+
+ @override
+ void initState() {
+ super.initState();
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ }
+
+ void getInitialData() async {
+ ///get previoues Attachment from Apis.
+ // isLoading = true;
+ setState(() {});
+ _attachments = widget.attachmentList;
+ // await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId, attachmentType: widget.attachmentType);
+ // isLoading = false;
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ log('value ${widget.attachmentType}');
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ appBar: DefaultAppBar(
+ title: 'Attachments'.addTranslation,
+ onBackPress: () {
+ Navigator.pop(context);
+ },
+ ),
+ body: widget.attachmentList.isEmpty
+ ? const NoDataFound().center
+ : Column(
+ children: [
+ Flexible(
+ fit: FlexFit.loose, // ✅ expands only as much as needed
+ child: Column(
+ children: [
+ widget.attachmentType == 5 && !widget.viewOnly
+ ? AttachmentPicker(
+ label: context.translation.attachments,
+ attachment: _attachments,
+ buttonColor: AppColor.primary10,
+ onlyImages: false,
+ showAsListView: true,
+ buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10),
+ onChange: (attachment) {},
+ ).toShadowContainer(
+ context,
+ borderRadius: 20,
+ padding: 12,
+ margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
+ )
+ : FilesList(images: _attachments.map((e) => 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: _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/change_status_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart
new file mode 100644
index 00000000..1eb16c9c
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/change_status_bottomsheet.dart
@@ -0,0 +1,69 @@
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+
+class AssetDeliveryBottomSheet {
+ static buildBottomSheetParent({required BuildContext context, required Widget childWidget, bool? isDismissible}) {
+ return showModalBottomSheet(
+ context: context,
+ useSafeArea: true,
+ isScrollControlled: true,
+ isDismissible: isDismissible ?? true,
+ backgroundColor: Colors.transparent,
+ builder: (context) => SingleChildScrollView(
+ child: SafeArea(child: childWidget),
+ ).bottomSheetContainer(context),
+ );
+ }
+
+ static Future changeStatusBottomSheet({required BuildContext context, required VoidCallback cancelStatusTap, required VoidCallback statusChangeTap}) {
+ return buildBottomSheetParent(
+ context: context,
+ childWidget: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const SizedBox().indicatorWidget(),
+ 8.height,
+ Align(
+ alignment: AlignmentDirectional.centerStart,
+ child: Text(
+ 'Change Status'.addTranslation,
+ style: TextStyle(
+ fontSize: 21.toScreenWidth,
+ fontWeight: FontWeight.w500,
+ fontStyle: FontStyle.normal,
+ decoration: TextDecoration.none,
+ ),
+ ),
+ ),
+ 16.height,
+ Row(
+ children: [
+ AppFilledButton(
+ label: 'Cancel'.addTranslation,
+ maxWidth: true,
+ buttonColor: Colors.white,
+ // textColor: context.isDark ? AppColor.neutral30 : Colors.white,
+ textColor: AppColor.red30,
+ showBorder: true,
+ onPressed: () async {
+ cancelStatusTap();
+ },
+ ).expanded,
+ 12.width,
+ AppFilledButton(
+ buttonColor: AppColor.green70,
+ label: 'Change Status'.addTranslation,
+ maxWidth: true,
+ onPressed: () {
+ statusChangeTap();
+ }).expanded,
+ ],
+ ),
+ ],
+ ));
+ }
+}
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
new file mode 100644
index 00000000..2fdfe356
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart
@@ -0,0 +1,457 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/enum_extensions.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/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';
+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/single_item_drop_down_menu.dart';
+
+class CostCenterFormView extends StatefulWidget {
+ final List? costCenterList;
+ final String? itemNo;
+ final String? itemDescription;
+ final int? lineId;
+ final int? tableItemId;
+ final int? requestId;
+ final bool? isHmg;
+ final double? cardPadding;
+
+ const CostCenterFormView({
+ super.key,
+ this.costCenterList,
+ this.lineId,
+ this.requestId,
+ this.tableItemId,
+ this.itemNo,
+ this.isHmg,
+ this.itemDescription,
+ this.cardPadding,
+ });
+
+ @override
+ State createState() => _CostCenterFormViewState();
+}
+
+class _CostCenterFormViewState extends State {
+ CostCenterSerialNoFormModel formModel = CostCenterSerialNoFormModel(costCenters: [], serialNos: []);
+ late AssetDeliveryProvider assetDeliveryProvider;
+ CostCenterType _selectedType = CostCenterType.costCenter;
+
+ @override
+ void initState() {
+ super.initState();
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ }
+
+ void getInitialData() async {
+ formModel = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines(
+ lineId: widget.lineId,
+ tableItemId: widget.tableItemId,
+ );
+ 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) {
+ await costCenterProvider.getData(id: widget.requestId);
+ }
+ }
+ setState(() {});
+ }
+
+ void addItem(List list, T Function() creator) {
+ setState(() {
+ list.add(creator());
+ });
+ }
+
+ void removeItem(List list, int index) {
+ setState(() {
+ list.removeAt(index);
+ });
+ }
+
+ void updateItem(List list, int index, void Function(T item) updater) {
+ setState(() {
+ updater(list[index]);
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ appBar: DefaultAppBar(
+ title: 'Cost Center for Item'.addTranslation,
+ // onBackPress: () {
+ // Navigator.pop(context);
+ // },
+ ),
+ body: Consumer(builder: (context, provider, child) {
+ return provider.isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ children: [
+ itemDetails(),
+ selectionButton(),
+ _selectedType == CostCenterType.costCenter ? _buildCostCenterList() : _buildSerialNumberList(),
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: 'Save'.addTranslation,
+ maxWidth: true,
+ onPressed: () async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ 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);
+ assetDeliveryProvider.getDeliveryLinesListById(
+ itemId: widget.tableItemId,
+ );
+ }
+ });
+ }),
+ ),
+ ],
+ );
+ }),
+ );
+ }
+
+ 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;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ 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),
+ ],
+ ),
+ );
+ }
+
+ 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 {
+ final CostCenterModel model;
+ final bool? isHmg;
+ final int index;
+ final int? requestId;
+ final bool isReadOnly;
+ final void Function(void Function(CostCenterModel model)) onUpdate;
+ final VoidCallback onRemove;
+
+ const CostCenterItemCard({
+ super.key,
+ required this.model,
+ this.requestId,
+ this.isHmg,
+ required this.index,
+ required this.isReadOnly,
+ required this.onUpdate,
+ required this.onRemove,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ if (!isReadOnly)
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ 'Cost Center'.addTranslation.bodyText(context).custom(color: AppColor.textColor(context)),
+ if (!isReadOnly)
+ Container(
+ height: 28,
+ width: 28,
+ padding: const EdgeInsets.all(6),
+ child: "trash".toSvgAsset(height: 20, width: 20),
+ ).onPress(onRemove),
+ ],
+ ),
+ 8.height,
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ isHmg == true
+ ? SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Cost Center'.addTranslation,
+ showShadow: false,
+ backgroundColor: AppColor.fieldBgColor(context),
+ requestById: requestId,
+ showAsBottomSheet: true,
+ matchBy: DropDownMatchType.name,
+ initialValue: model.costCenter,
+ onSelect: (status) {
+ if (status != null) {
+ model.costCenter = status;
+ model.costCenterName = status.name;
+ }
+ },
+ )
+ : AppTextFormField(
+ labelText: 'Cost Center'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.costCenterName ?? '',
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ onChange: (value) {
+ model.costCenterName = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Quantity'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.quantity != null ? model.quantity.toString() : '',
+ textAlign: TextAlign.center,
+ enable: true,
+ textInputType: TextInputType.number,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ onChange: (value) {
+ if (value.isNotEmpty) {
+ model.quantity = double.tryParse(value);
+ }
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ],
+ )
+ ],
+ ).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
new file mode 100644
index 00000000..2d113140
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart
@@ -0,0 +1,726 @@
+import 'dart:convert';
+import 'dart:developer';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/enum_extensions.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/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/asset_delivery_stage_tab_page.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/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/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';
+
+class DeliveryInspectionFormView extends StatefulWidget {
+ static const String id = "/delivery-inspection-form";
+ final AssetDeliveryTableModel deliveryTableModel;
+ final AssetDeliveryDataModel? requestModel;
+
+ DeliveryInspectionFormView({
+ Key? key,
+ required this.deliveryTableModel,
+ this.requestModel,
+ }) : super(key: key);
+
+ @override
+ State createState() => _DeliveryInspectionFormViewState();
+}
+
+class _DeliveryInspectionFormViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ bool viewOnly = false;
+ AssetDeliveryProvider? assetDeliveryProvider;
+ DeliveryInspectionFormModel model = DeliveryInspectionFormModel();
+ bool isLoading = false;
+
+ @override
+ void initState() {
+ viewOnly = widget.deliveryTableModel.status?.value != 2;
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ void getInitialData() async {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ setState(() {
+ isLoading = true;
+ });
+ final results = await Future.wait([
+ assetDeliveryProvider!.getAssetDeliveryInspectionData(
+ itemId: widget.deliveryTableModel.id,
+ ),
+ assetDeliveryProvider!.getDeliveryLinesListById(
+ itemId: widget.deliveryTableModel.id,
+ ),
+ ]);
+ model = results[0] as DeliveryInspectionFormModel;
+ setState(() {
+ isLoading = false;
+ });
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ // appBar: DefaultAppBar(
+ // title: 'Delivery Inspection'.addTranslation,
+ // onBackPress: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ body: isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (!viewOnly) ...[inspectionDetailsForm()] else ...[inspectionDetails()],
+ 8.height,
+ Text(
+ 'Total Time'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ formatInspectionDuration(model.totalTime),
+ style: AppTextStyles.bodyText2.copyWith(
+ color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
+ ),
+ ),
+
+ // Text(
+ // model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
+ // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ // ),
+ 8.height,
+ const Divider().defaultStyle(context),
+ Text(
+ "Lines",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ linesList(context),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12))
+ .expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: !viewOnly
+ ? Column(
+ children: [
+ AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: 'Attachments'.addTranslation,
+ maxWidth: true,
+ onPressed: () {
+ HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ }),
+ 16.height,
+ Row(
+ children: [
+ AppFilledButton(
+ label: 'Cancel'.addTranslation,
+ maxWidth: true,
+ buttonColor: AppColor.background(context),
+ // textColor: context.isDark ? AppColor.neutral30 : Colors.white,
+ textColor: AppColor.red30,
+ showBorder: true,
+ onPressed: _cancelTap,
+ ).expanded,
+ 12.width,
+ AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
+ ],
+ ),
+ ],
+ )
+ : Row(
+ children: [
+ AppFilledButton(
+ buttonColor: AppColor.white60,
+ label: 'Attachments'.addTranslation,
+ maxWidth: true,
+ textColor: AppColor.black10,
+ onPressed: () {
+ HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ }).expanded,
+ 8.width,
+ AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded,
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget linesList(BuildContext context) {
+ return Consumer(builder: (context, provider, child) {
+ List linesList = provider.deliveryLinesList;
+ return provider.isDeliveryLineListLoading
+ ? SizedBox.expand(child: const CircularProgressIndicator(color: AppColor.primary10).center)
+ : linesList.isEmpty
+ ? const NoDataFound().center
+ : ListView.separated(
+ itemCount: linesList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ DeliveryLineModel model = linesList[itemIndex];
+ return AssetDeliveryLineCard(
+ deliveryLineModel: model,
+ isViewOnly: viewOnly,
+ editPress: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => CostCenterFormView(
+ itemNo: model.itemNumber,
+ lineId: model.id,
+ isHmg: widget.requestModel?.isHMG,
+ tableItemId: widget.deliveryTableModel.id,
+ requestId: widget.requestModel?.id,
+ itemDescription: model.itemDescription,
+ )));
+ },
+ );
+ },
+ );
+ });
+ }
+
+ void calculateTotalTime() {
+ final from = model.deliveryInspectionInspectedDateFrom;
+ final to = model.deliveryInspectionInspectedDateTo;
+
+ if (from == null || to == null) {
+ model.totalTime = null;
+ return;
+ }
+
+ final diffInSeconds = to.difference(from).inSeconds;
+
+ if (diffInSeconds < 0) {
+ model.totalTime = null;
+ return;
+ }
+
+ final hours = diffInSeconds / 3600;
+ model.totalTime = num.parse(hours.toStringAsFixed(3));
+ }
+
+ Widget inspectionDetailsForm() {
+ return Column(
+ children: [
+ _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) ...[
+ 8.height,
+ _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);
+ }
+ },
+ ),
+ ],
+
+ // 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,
+ hideShadow: true,
+ height: 56.toScreenHeight,
+ backgroundColor: AppColor.fieldBgColor(context),
+ date: model.deliveryInspectionInspectedDateFrom,
+ from: DateTime(DateTime.now().year, 1, 1),
+ formatDateWithTime: true,
+ onDatePicker: (selectedDate) async {
+ final selectedTime = await showTimePicker(
+ context: context,
+ initialTime: TimeOfDay.now(),
+ builder: _timePickerThemeBuilder,
+ );
+ if (selectedTime == null) return;
+
+ final fromDateTime = DateTime(
+ selectedDate.year,
+ selectedDate.month,
+ selectedDate.day,
+ selectedTime.hour,
+ selectedTime.minute,
+ );
+
+ if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) {
+ return; // invalid, do not assign
+ }
+
+ model.deliveryInspectionInspectedDateFrom = fromDateTime;
+ setState(() {});
+ },
+ ),
+
+ 8.height,
+ ADatePicker(
+ label: 'Inspected Date/Time To'.addTranslation,
+ hideShadow: true,
+ height: 56.toScreenHeight,
+ backgroundColor: AppColor.fieldBgColor(context),
+ date: model.deliveryInspectionInspectedDateTo,
+ from: model.deliveryInspectionInspectedDateFrom,
+ formatDateWithTime: true,
+ onDatePicker: (selectedDate) async {
+ if (model.deliveryInspectionInspectedDateFrom == null) {
+ "Please select time to first".showToast;
+ return;
+ }
+
+ final selectedTime = await showTimePicker(
+ context: context,
+ initialTime: TimeOfDay.now(),
+ builder: _timePickerThemeBuilder,
+ );
+ if (selectedTime == null) return;
+
+ final toDateTime = DateTime(
+ selectedDate.year,
+ selectedDate.month,
+ selectedDate.day,
+ selectedTime.hour,
+ selectedTime.minute,
+ );
+
+ if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) {
+ return; // invalid, do not assign
+ }
+
+ model.deliveryInspectionInspectedDateTo = toDateTime;
+ setState(() {});
+ },
+ ),
+ ],
+ );
+ }
+
+ bool _validateInspectionDates({DateTime? from, DateTime? to}) {
+ if (from == null && to == null) return true;
+ if (from != null) {
+ if (from.isAfter(DateTime.now())) {
+ "Time From cannot be in the future".showToast;
+ return false;
+ }
+ if (to != null && from.isAfter(to)) {
+ "Time To cannot be after Time From".showToast;
+ return false;
+ }
+ }
+ if (to != null) {
+ if (to.isAfter(DateTime.now())) {
+ "Time To cannot be in the future".showToast;
+ return false;
+ }
+ if (from != null && to.isBefore(from)) {
+ "Timer To cannot be before from time".showToast;
+ return false;
+ }
+ }
+
+ if (from != null && to != null) {
+ final diffInSeconds = to.difference(from).inSeconds;
+ if (diffInSeconds < 0) {
+ model.totalTime = null;
+ return false;
+ }
+ final hours = diffInSeconds / 3600.0;
+ model.totalTime = num.parse(hours.toStringAsFixed(3));
+ } else {
+ model.totalTime = null;
+ }
+
+ return true;
+ }
+
+ String formatInspectionDuration(num? hours) {
+ if (hours == null) return '-';
+
+ if (hours < 1) {
+ final minutes = (hours * 60).round();
+ return '$minutes minutes';
+ }
+
+ return '${hours.toStringAsFixed(2)} hours';
+ }
+
+ Widget _timePickerThemeBuilder(BuildContext context, Widget? child) {
+ final ThemeData currentTheme = Theme.of(context);
+
+ return Theme(
+ data: currentTheme.copyWith(
+ timePickerTheme: TimePickerThemeData(
+ dialHandColor: AppColor.primary10,
+ dialBackgroundColor: Colors.grey.withOpacity(0.1),
+ hourMinuteColor: MaterialStateColor.resolveWith(
+ (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1),
+ ),
+ dayPeriodColor: MaterialStateColor.resolveWith(
+ (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent,
+ ),
+ dayPeriodTextColor: MaterialStateColor.resolveWith(
+ (states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10,
+ ),
+ dayPeriodBorderSide: BorderSide(
+ color: Colors.grey.withOpacity(0.2),
+ ),
+ entryModeIconColor: AppColor.primary10,
+ ),
+ textButtonTheme: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ foregroundColor: AppColor.primary10,
+ ),
+ ),
+ ),
+ child: child!,
+ );
+ }
+
+ Widget inspectionDetails() {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Inspected by'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ model.deliveryInspectionInspectedBy ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Approved by'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ model.deliveryInspectionApprovedBy ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Inspected Date/Time From'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ model.deliveryInspectionInspectedDateFrom != null ? model.deliveryInspectionInspectedDateFrom!.toString().toServiceRequestDetailsFormat : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Inspected Date/Time To'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ model.deliveryInspectionInspectedDateTo != null ? model.deliveryInspectionInspectedDateTo!.toString().toServiceRequestDetailsFormat : '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ],
+ );
+ }
+
+ 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 {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider!.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ void _nextTap() {
+ if (widget.deliveryTableModel.isContainsTechnicalInspection == true) {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => TechnicalInspectionLinesListView(
+ // deliveryTableModel: widget.deliveryTableModel,
+ // requestModel: widget.requestModel,
+ // ))
+ // );
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => AssetDeliveryStageTabPage(
+ title: 'Technical Inspection'.addTranslation,
+ detailWidget: TechnicalInspectionLinesListView(
+ deliveryTableModel: widget.deliveryTableModel,
+ requestModel: widget.requestModel,
+ ),
+ tableId: widget.deliveryTableModel.id,
+ )));
+ } else {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => AssetDeliveryStageTabPage(
+ title: 'End-User Acceptance'.addTranslation,
+ detailWidget: EndUserCostCenterLIstView(
+ deliveryTableModel: widget.deliveryTableModel,
+ requestModel: widget.requestModel,
+ ),
+ tableId: widget.deliveryTableModel.id,
+ )));
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => EndUserCostCenterLIstView(
+ // deliveryTableModel: widget.deliveryTableModel,
+ // requestModel: widget.requestModel,
+ // )));
+ }
+ }
+
+ void _changeStatusTap() async {
+ _formKey.currentState!.save();
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ model.assetDeliveryExternalDeliveryId = widget.deliveryTableModel.id;
+ await assetDeliveryProvider!.changeDeliveryStatus(requestPayload: model.toJson()).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider!.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ 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..434f3382
--- /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 ?? '');
+ }
+
+ @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 ?? '';
+ emailController.text = value.employeeEmail ?? '';
+ 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,
+ enable: widget.isHmg?false:true,
+ 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/delivery_inspection/oracle_user_autocomplete_field.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart
new file mode 100644
index 00000000..9c18de9b
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart
@@ -0,0 +1,117 @@
+import 'dart:developer';
+
+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/text_extensions.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/oracle_user_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/app_style/app_text_style.dart';
+import 'package:test_sa/views/app_style/sizing.dart';
+
+class OracleUserAutoCompleteField extends StatefulWidget {
+ final String initialValue;
+ final String label;
+ final bool clearAfterPick;
+ final Function(OracleUserModel) onPick;
+ final Function(String)? onChanged;
+
+ const OracleUserAutoCompleteField({Key? key, required this.initialValue, required this.label, required this.onPick, this.clearAfterPick = true, this.onChanged}) : super(key: key);
+
+ @override
+ _AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState();
+}
+
+class _AutoCompletePartsFieldState extends State {
+ AssetDeliveryProvider? assetDeliveryProvider;
+
+ // late TextEditingController _controller;
+
+ @override
+ void initState() {
+ // _controller = TextEditingController(text: widget.initialValue);
+ super.initState();
+ }
+
+ @override
+ void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) {
+ // if (widget.initialValue != oldWidget.initialValue) {
+ // _controller = TextEditingController(text: widget.initialValue);
+ // }
+ super.didUpdateWidget(oldWidget);
+ }
+
+ @override
+ void dispose() {
+ // _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ assetDeliveryProvider ??= Provider.of(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(
+ key: ValueKey(widget.initialValue),
+ optionsBuilder: (TextEditingValue textEditingValue) async {
+ if (textEditingValue.text.isEmpty) {
+ return const Iterable.empty();
+ }
+ return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text);
+ },
+ initialValue: TextEditingValue(text: widget.initialValue),
+ displayStringForOption: (OracleUserModel option) => option.fullName ?? "",
+ fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
+ return TextField(
+ controller: fieldTextEditingController,
+ 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(minWidth: 0),
+ 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: widget.label,
+ labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
+ ),
+ textInputAction: TextInputAction.search,
+ onChanged: (text) {
+ if (widget.onChanged != null) {
+ widget.onChanged!(text);
+ fieldTextEditingController.text = text;
+ }
+ },
+ onSubmitted: (String value) {
+ onFieldSubmitted();
+ },
+ );
+ },
+ onSelected: (OracleUserModel selection) {
+ // if (widget.clearAfterPick) {
+ // fieldTextEditingController.clear();
+ // } else {
+ // _controller.text = selection.fullName ?? '';
+ // }
+ widget.onPick(selection);
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart
new file mode 100644
index 00000000..59237ffd
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart
@@ -0,0 +1,64 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/asset_delivery_module/models/cost_center_model.dart';
+import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+
+class EndUserCostCenterCardView extends StatelessWidget {
+ CostCenterModel costModel;
+ VoidCallback? editPress;
+ bool isViewOnly;
+
+ EndUserCostCenterCardView({
+ super.key,
+ required this.costModel,
+ this.editPress,
+ required this.isViewOnly,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ //need to check this @waseem.
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: Text(
+ 'Cost Center Name: ${costModel.costCenterName ?? '-'}',
+ overflow: TextOverflow.ellipsis,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ),
+ 8.width,
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset(height: 18, width: 18).onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ Text(
+ 'Accepted By: ${costModel.acceptedBy ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),Text(
+ 'Accepted By Email: ${costModel.acceptedByEmail ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),Text(
+ 'Acceptance Date: ${costModel.acceptanceDate!=null? costModel.acceptanceDate.toString().toAssetDetailsFormat: '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart
new file mode 100644
index 00000000..f023c938
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.dart
@@ -0,0 +1,118 @@
+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/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class EndUserAssetDetailCard extends StatelessWidget {
+ EndUserAssetDetailsModel assetModel;
+ bool isViewOnly;
+ VoidCallback? editPress;
+
+ EndUserAssetDetailCard({
+ super.key,
+ required this.isViewOnly,
+ required this.assetModel,
+ this.editPress,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ assetModel.status != null
+ ? StatusLabel(
+ label: assetModel.status?.name,
+ radius: 4,
+ textColor: getAssetStatusColor(context: context, status: assetModel.status?.name ?? '', isBackground: false),
+ backgroundColor: getAssetStatusColor(context: context, status: assetModel.status?.name ?? ''),
+ )
+ : const SizedBox(),
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset().onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ 8.height,
+ if (assetModel.type == 'Accessory') ...[
+ Text(
+ 'Type: ${assetModel.type ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Item Number: ${assetModel.itemNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Received Quantity: ${assetModel.receivedQty ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Rejected Quantity: ${assetModel.rejectedQty ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Description: ${assetModel.description ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ] else ...[
+ Text(
+ 'Type: ${assetModel.type ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Item Number: ${assetModel.itemNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Asset Number: ${assetModel.assetNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Serial No: ${assetModel.serialNo ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Replaced Asset No: ${assetModel.replacedAssetNo ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ //TODO Need to confirm with @Ahmed need to hide this or not
+ if (assetModel.status?.value == 2)
+ Text(
+ 'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Description: ${assetModel.description ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+
+ Color getAssetStatusColor({required BuildContext context, required String status, bool? isBackground = true}) {
+ switch (status) {
+ case 'Accept':
+ return isBackground! ? AppColor.green70.withOpacity(0.4) : AppColor.green15;
+ case 'Reject':
+ return isBackground! ? AppColor.red30.withOpacity(0.4) : AppColor.red30;
+ default:
+ return Colors.blueGrey;
+ }
+ }
+}
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
new file mode 100644
index 00000000..f032d75a
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart
@@ -0,0 +1,198 @@
+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/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';
+import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/cost_center_card_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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 '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class EndUserCostCenterLIstView extends StatefulWidget {
+ final AssetDeliveryTableModel deliveryTableModel;
+ final AssetDeliveryDataModel? requestModel;
+
+ EndUserCostCenterLIstView({
+ Key? key,
+ required this.deliveryTableModel,
+ this.requestModel,
+ }) : super(key: key);
+
+ @override
+ State createState() => _EndUserCostCenterLIstViewState();
+}
+
+class _EndUserCostCenterLIstViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ bool viewOnly = false;
+ List costCenterList = [];
+ AssetDeliveryProvider? assetDeliveryProvider;
+ bool isLoading = false;
+
+ @override
+ void initState() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ void getInitialData() async {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ isLoading = true;
+ if (widget.deliveryTableModel.status?.value != null && widget.deliveryTableModel.status!.value! > 4) {
+ viewOnly = true;
+ }
+ setState(() {});
+ costCenterList = (await assetDeliveryProvider?.getEndUserCostCenterList(
+ tableItemId: widget.deliveryTableModel.id,
+ )) ??
+ [];
+ isLoading = false;
+ setState(() {});
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ // appBar: DefaultAppBar(
+ // title: 'End-User Acceptance'.addTranslation,
+ // titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ // ),
+ body: Form(
+ key: _formKey,
+ child: isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ children: [
+ //Refactor this
+ SingleChildScrollView(padding: const EdgeInsets.all(16), child: linesList(context).toShadowContainer(context, borderRadius: 20, padding: 12)).expanded,
+
+ !viewOnly
+ ? FooterActionButton.footerContainer(
+ context: context,
+ child: Column(
+ children: [
+ AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
+ 16.height,
+ Row(
+ children: [
+ AppFilledButton(
+ label: 'Cancel'.addTranslation,
+ maxWidth: true,
+ buttonColor: AppColor.background(context),
+ textColor: AppColor.red30,
+ showBorder: true,
+ onPressed: _cancelTap,
+ ).expanded,
+ 12.width,
+ AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
+ ],
+ ),
+ ],
+ ))
+ : FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.white60,
+ label: 'Attachments'.addTranslation,
+ maxWidth: true,
+ textColor: AppColor.black10,
+ onPressed: () {
+ HelperFunction.attachmentTap(context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ }),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ //Need to refector don't use listview and singlechildview both @waseem.
+ Widget linesList(BuildContext context) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Cost Center",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ ListView.separated(
+ itemCount: costCenterList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ return EndUserCostCenterCardView(
+ costModel: costCenterList[itemIndex],
+ isViewOnly: viewOnly,
+ editPress: () async {
+ bool isRefresh = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UpdateEndUserCostCenterDetailsView(
+ costCenterModel: costCenterList[itemIndex],
+ tableItemId: widget.deliveryTableModel.id,
+ isHmg: widget.requestModel?.isHMG,
+ )));
+ if (isRefresh) {
+ getInitialData();
+ }
+ },
+ );
+ },
+ ),
+ ],
+ );
+ }
+
+ void _attachmentTap() async {
+ HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ }
+
+ void _cancelTap() async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider?.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ void _changeStatusTap() async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider?.changeDeliveryStatus(itemId: widget.deliveryTableModel.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ void _nextTap() async {
+ // Navigator.push(context, MaterialPageRoute(builder: (context) => EndUserCostCenterLIstView()));
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart
new file mode 100644
index 00000000..834b96b3
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_asset_details_view.dart
@@ -0,0 +1,520 @@
+// import 'dart:developer';
+//
+// import 'package:flutter/foundation.dart';
+// 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/lookup.dart';
+// import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
+// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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';
+// 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/single_item_drop_down_menu.dart';
+// import '../../../../new_views/common_widgets/app_filled_button.dart';
+// import '../../../../new_views/common_widgets/default_app_bar.dart';
+//
+// class UpdateEndUserAssetDetailsView extends StatefulWidget {
+// EndUserAssetDetailsModel? assetDetailsModel;
+// String? costCenterName;
+// int? tableId;
+//
+// UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key);
+//
+// @override
+// State createState() => _UpdateEndUserAssetDetailsViewState();
+// }
+//
+// class _UpdateEndUserAssetDetailsViewState extends State {
+// final GlobalKey _formKey = GlobalKey();
+// final GlobalKey _scaffoldKey = GlobalKey();
+// bool viewOnly = false;
+// late AssetDeliveryProvider assetDeliveryProvider;
+// EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
+// late TextEditingController quantityController;
+// late TextEditingController descriptionController;
+//
+// @override
+// void initState() {
+// quantityController = TextEditingController();
+// descriptionController = TextEditingController();
+// WidgetsBinding.instance.addPostFrameCallback((_) {
+// getInitialData();
+// });
+// super.initState();
+// }
+//
+// @override
+// void dispose() {
+// super.dispose();
+// }
+//
+// void getInitialData() async {
+// assetDeliveryProvider = Provider.of(context, listen: false);
+// if (widget.assetDetailsModel != null) {
+// model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson());
+// model.costCenterName = widget.costCenterName;
+// model.assetDeliveryExternalDeliveryId = widget.tableId;
+// model.status = widget.assetDetailsModel?.status;
+// model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
+// }
+// quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
+// descriptionController.text = model.description ?? '';
+// model.type = 'Accessory';
+// setState(() {});
+// }
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// key: _scaffoldKey,
+// appBar: DefaultAppBar(
+// title: 'Item Details'.addTranslation,
+// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+// ),
+// body: Form(
+// key: _formKey,
+// child: Column(
+// children: [
+// SingleChildScrollView(
+// padding: const EdgeInsets.all(16),
+// child: Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// children: [
+// SingleItemDropDownMenu(
+// context: context,
+// height: 56.toScreenHeight,
+// title: 'Status'.addTranslation,
+// titleTextColor: AppColor.neutral120,
+// showShadow: false,
+// validator: (value) {
+// if (value == null) return "Please select status";
+// return null;
+// },
+// backgroundColor: AppColor.fieldBgColor(context),
+// showAsBottomSheet: true,
+// initialValue: model.status,
+// onSelect: (status) {
+// if (status != null) {
+// model.status = status;
+// setState(() {});
+// }
+// },
+// ),
+// 8.height,
+// if (model.type == 'Accessory') ...[
+// AppTextFormField(
+// labelText: 'Rejected Quantity'.addTranslation,
+// controller: quantityController,
+// backgroundColor: AppColor.fieldBgColor(context),
+// textAlign: TextAlign.center,
+// labelStyle: AppTextStyles.textFieldLabelStyle,
+// textInputType: TextInputType.number,
+// showShadow: false,
+// validator: (value) {
+// if ((value ?? "").isEmpty) return "Mandatory";
+// return null;
+// },
+// onChange: (value) {
+// if (value.isNotEmpty) {
+// model.rejectedQty = model.rejectedQty = num.tryParse(value);
+// setState(() {});
+// }
+// },
+// style: Theme.of(context).textTheme.titleMedium,
+// ),
+// 8.height,
+// if (model.status?.value == 1 && (model.rejectedQty != null && quantityController.text.isNotEmpty && model.rejectedQty! > 0))
+// SingleItemDropDownMenu(
+// context: context,
+// height: 56.toScreenHeight,
+// title: 'Rejection Reason '.addTranslation,
+// validator: (value) {
+// if (value == null) return "Please select rejection reason";
+// return null;
+// },
+// titleTextColor: AppColor.neutral120,
+// showShadow: false,
+// backgroundColor: AppColor.fieldBgColor(context),
+// showAsBottomSheet: true,
+// initialValue: model.rejectionReason,
+// onSelect: (reason) {
+// if (reason != null) {
+// model.rejectionReason = reason;
+// setState(() {});
+// }
+// },
+// ),
+// 8.height,
+// ],
+// if (model.status != null && model.status!.value == 2) ...[
+// SingleItemDropDownMenu(
+// context: context,
+// height: 56.toScreenHeight,
+// title: 'Rejection Reason '.addTranslation,
+// validator: (value) {
+// if (value == null) return "Please select rejection reason";
+// return null;
+// },
+// titleTextColor: AppColor.neutral120,
+// showShadow: false,
+// backgroundColor: AppColor.fieldBgColor(context),
+// showAsBottomSheet: true,
+// initialValue: model.rejectionReason,
+// onSelect: (reason) {
+// if (reason != null) {
+// model.rejectionReason = reason;
+// setState(() {});
+// }
+// },
+// ),
+// 8.height,
+// ],
+// AppTextFormField(
+// controller: descriptionController,
+// labelText: 'Description'.addTranslation,
+// backgroundColor: AppColor.fieldBgColor(context),
+// showShadow: false,
+// labelStyle: AppTextStyles.textFieldLabelStyle,
+// alignLabelWithHint: true,
+// textInputType: TextInputType.multiline,
+// onChange: (value) {
+// model.description = value;
+// },
+// onSaved: (value) {
+// model.description = value;
+// },
+// ),
+// 8.height,
+// ],
+// ).toShadowContainer(context, borderRadius: 20, padding: 12))
+// .expanded,
+// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
+// ],
+// ),
+// ),
+// );
+// }
+//
+// ///Need to check which details show here...
+//
+// void _saveTap() async {
+// if (!_formKey.currentState!.validate()) {
+// return;
+// }
+// _formKey.currentState!.save();
+// log('payload ${model.toJson()}');
+// return;
+// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+// await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async {
+// Navigator.pop(context);
+// if (status) {
+// Navigator.pop(context, true);
+// }
+// });
+// }
+// }
+
+import 'dart:developer';
+
+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/lookup.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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';
+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/single_item_drop_down_menu.dart';
+import '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class UpdateEndUserAssetDetailsView extends StatefulWidget {
+ final EndUserAssetDetailsModel? assetDetailsModel;
+ final String? costCenterName;
+ final int? tableId;
+
+ const UpdateEndUserAssetDetailsView({
+ Key? key,
+ this.assetDetailsModel,
+ this.costCenterName,
+ this.tableId,
+ }) : super(key: key);
+
+ @override
+ State createState() => _UpdateEndUserAssetDetailsViewState();
+}
+
+class _UpdateEndUserAssetDetailsViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+
+ late AssetDeliveryProvider assetDeliveryProvider;
+ EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
+
+ late TextEditingController quantityController;
+ late TextEditingController descriptionController;
+
+ @override
+ void initState() {
+ super.initState();
+ quantityController = TextEditingController();
+ descriptionController = TextEditingController();
+
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ _loadInitialData();
+ });
+ }
+
+ void _loadInitialData() {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ if (widget.assetDetailsModel != null) {
+ model = EndUserAssetDetailsModel.fromJson(
+ widget.assetDetailsModel!.toJson(),
+ );
+ model.costCenterName = widget.costCenterName;
+ model.assetDeliveryExternalDeliveryId = widget.tableId;
+ model.status = widget.assetDetailsModel?.status;
+ model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
+ model.receivedQty = widget.assetDetailsModel?.receivedQty;
+ }
+
+ quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
+ descriptionController.text = model.description ?? '';
+ setState(() {});
+ }
+
+ bool get _isAccessory => model.type == 'Accessory';
+
+ bool get _isAccepted => model.status?.value == 1;
+
+ bool get _isRejected => model.status?.value == 2;
+
+ bool get _showRejectedQty {
+ if (_isAccessory) return true;
+ return false;
+ }
+
+ bool get _showReceivedQty {
+ if (_isAccessory && model.receivedQty != null) return true;
+ return false;
+ }
+
+ bool get _showRejectionReason {
+ if (_isAccessory) {
+ if (_isRejected) return true;
+ if (_isAccepted && (model.rejectedQty ?? 0) > 0) return true;
+ return false;
+ }
+ if (_isRejected) return true;
+ return false;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: DefaultAppBar(
+ title: 'Item Details'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(
+ fontWeight: FontWeight.w500,
+ color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
+ ),
+ ),
+ body: Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: _formBody(context),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: 'Save'.addTranslation,
+ maxWidth: true,
+ onPressed: _saveTap,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget _formBody(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ _statusDropdown(),
+ 8.height,
+ if (_showReceivedQty) ...[
+ _receivedQtyField(),
+ 8.height,
+ ],
+ if (_showRejectedQty) ...[
+ _rejectedQtyField(),
+ 8.height,
+ ],
+ if (_showRejectionReason) ...[
+ _rejectionReasonDropdown(),
+ 8.height,
+ ],
+ _descriptionField(),
+ 8.height,
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+
+ Widget _statusDropdown() {
+ return SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Status'.addTranslation,
+ titleTextColor: AppColor.neutral120,
+ showShadow: false,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ initialValue: model.status,
+ validator: (value) {
+ if (value == null) return 'Please select status';
+ return null;
+ },
+ onSelect: (status) {
+ if (status != null) {
+ model.status = status;
+ model.rejectionReason = null;
+ setState(() {});
+ }
+ },
+ );
+ }
+
+ Widget _rejectedQtyField() {
+ return AppTextFormField(
+ labelText: 'Rejected Quantity'.addTranslation,
+ controller: quantityController,
+ backgroundColor: AppColor.fieldBgColor(context),
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ validator: (value) {
+ if (!_showRejectedQty) return null;
+ if ((value ?? '').isEmpty) return 'Mandatory';
+ final qty = num.tryParse(value!);
+ if (qty == null || qty <= 0) return 'Enter valid quantity';
+ return null;
+ },
+ onChange: (value) {
+ model.rejectedQty = value.isNotEmpty ? num.tryParse(value) : null;
+ setState(() {});
+ },
+ );
+ }
+
+ Widget _receivedQtyField() {
+ return Container(
+ padding: const EdgeInsets.all(12),
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: AppColor.neutral40,
+ // color: AppColor.fieldBgColor(context),
+ borderRadius: BorderRadius.circular(12),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text('Received Qty', style: AppTextStyles.textFieldLabelStyle),
+ 4.height,
+ Text(model.receivedQty.toString(), style: AppTextStyles.textFieldLabelStyle),
+ ],
+ ),
+ );
+
+ AppTextFormField(
+ labelText: 'Received Quantity'.addTranslation,
+ initialValue: model.receivedQty.toString(),
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ enable: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ );
+ }
+
+ Widget _rejectionReasonDropdown() {
+ return SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Rejection Reason'.addTranslation,
+ titleTextColor: AppColor.neutral120,
+ showShadow: false,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ initialValue: model.rejectionReason,
+ validator: (value) {
+ if (!_showRejectionReason) return null;
+ if (value == null) return 'Please select rejection reason';
+ return null;
+ },
+ onSelect: (reason) {
+ if (reason != null) {
+ model.rejectionReason = reason;
+ setState(() {});
+ }
+ },
+ );
+ }
+
+ Widget _descriptionField() {
+ return AppTextFormField(
+ controller: descriptionController,
+ labelText: 'Description'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showShadow: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ alignLabelWithHint: true,
+ textInputType: TextInputType.multiline,
+ onChange: (value) => model.description = value,
+ onSaved: (value) => model.description = value,
+ );
+ }
+
+ void _saveTap() async {
+ if (!_formKey.currentState!.validate()) return;
+
+ _formKey.currentState!.save();
+ log('payload ${model.toJson()}');
+
+ showDialog(
+ context: context,
+ barrierDismissible: false,
+ builder: (_) => const AppLazyLoading(),
+ );
+
+ final status = await assetDeliveryProvider.saveEndUserAssetDataData(model: model);
+
+ Navigator.pop(context);
+
+ if (status) {
+ Navigator.pop(context, true);
+ }
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart
new file mode 100644
index 00000000..1234a018
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart
@@ -0,0 +1,331 @@
+import 'dart:convert';
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.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/asset_delivery_module/models/cost_center_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_asset_detail_card.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/end_user_acceptance/update_end_user_asset_details_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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/views/widgets/date_and_time/date_picker.dart';
+import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
+import '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class UpdateEndUserCostCenterDetailsView extends StatefulWidget {
+ int? tableItemId;
+ CostCenterModel? costCenterModel;
+ bool? isHmg;
+
+ UpdateEndUserCostCenterDetailsView({
+ Key? key,
+ this.tableItemId,
+ this.costCenterModel,
+ this.isHmg,
+ }) : super(key: key);
+
+ @override
+ State createState() => _UpdateEndUserCostCenterDetailsViewState();
+}
+
+class _UpdateEndUserCostCenterDetailsViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ bool viewOnly = false;
+ CostCenterModel model = CostCenterModel();
+ List assetList = [];
+ late AssetDeliveryProvider assetDeliveryProvider;
+ Uint8List? newSignature;
+ String? endUserSignature;
+ bool isLoading = false;
+ late TextEditingController acceptedByController;
+ late TextEditingController acceptedByEmailController;
+
+ @override
+ void initState() {
+ acceptedByController = TextEditingController();
+ acceptedByEmailController = TextEditingController();
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ void getInitialData() async {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+
+ if (widget.costCenterModel != null) {
+ model = CostCenterModel.fromJson(widget.costCenterModel!.toEndUserAcceptanceFormJson());
+ _fillControllers();
+ }
+ setState(() {
+ isLoading = true;
+ });
+ assetList = await assetDeliveryProvider.getEndUserAssetList(tableItemId: widget.tableItemId, costCenterName: widget.costCenterModel?.costCenterName);
+ setState(() {
+ isLoading = false;
+ });
+ }
+
+ void _fillControllers() {
+ acceptedByController.text = model.acceptedBy ?? '';
+ acceptedByEmailController.text = model.acceptedByEmail ?? '';
+ }
+
+ @override
+ void dispose() {
+ acceptedByController.dispose();
+ acceptedByEmailController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(
+ title: 'End-User Acceptance'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ body: Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ inspectionDetailsForm(),
+ 8.height,
+ const Divider().defaultStyle(context),
+
+ ///Need to implement later as discuss with Ahmed.
+ // Text(
+ // "Acceptance Form",
+ // style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ // ),
+ // 6.height,
+ // Row(
+ // children: [
+ // 'warning_icon'.toSvgAsset(height: 16, width: 16),
+ // 6.width,
+ // Text(
+ // 'Review the acceptance form'.addTranslation,
+ // style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ // ),
+ // 6.width,
+ // 'web_link_icon'.toSvgAsset(height: 20, width: 20),
+ // ],
+ // ),
+ 16.height,
+ Text(
+ "Items",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ endUserAssetList(context),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12))
+ .expanded,
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget endUserAssetList(BuildContext context) {
+ return isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : ListView.separated(
+ itemCount: assetList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ EndUserAssetDetailsModel model = assetList[itemIndex];
+ return EndUserAssetDetailCard(
+ assetModel: model,
+ isViewOnly: viewOnly,
+ editPress: () async {
+ bool isRefresh = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UpdateEndUserAssetDetailsView(
+ assetDetailsModel: model,
+ costCenterName: widget.costCenterModel?.costCenterName,
+ tableId: widget.tableItemId,
+ )));
+ if (isRefresh) {
+ getInitialData();
+ }
+ },
+ );
+ },
+ );
+ }
+
+ Widget inspectionDetailsForm() {
+ return Column(
+ children: [
+ ADatePicker(
+ label: 'Accepted Date'.addTranslation,
+ hideShadow: true,
+ height: 56.toScreenHeight,
+ backgroundColor: AppColor.fieldBgColor(context),
+ date: model.acceptanceDate,
+ from: DateTime(DateTime.now().year, 1, 1),
+ formatDateWithTime: true,
+ onDatePicker: (selectedDate) {
+ showTimePicker(
+ context: context,
+ initialTime: TimeOfDay.now(),
+ builder: (BuildContext context, Widget? child) {
+ final ThemeData currentTheme = Theme.of(context);
+ return Theme(
+ data: currentTheme.copyWith(
+ timePickerTheme: TimePickerThemeData(
+ dialHandColor: AppColor.primary10,
+ dialBackgroundColor: Colors.grey.withOpacity(0.1),
+ hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
+ dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
+ dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
+ dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
+ entryModeIconColor: AppColor.primary10,
+ ),
+ textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
+ ),
+ child: child!,
+ );
+ },
+ ).then((selectedTime) {
+ if (selectedTime != null) {
+ model.acceptanceDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
+ setState(() {});
+ }
+ });
+ },
+ ),
+ 8.height,
+ if (widget.isHmg == true) ...[
+ OracleUserAutoCompleteField(
+ clearAfterPick: false,
+ initialValue: model.acceptedBy ?? '',
+ label: 'Accepted By'.addTranslation,
+ onPick: (value) {
+ model.acceptedBy = value.fullName;
+ model.acceptedByEmail = value.employeeEmail;
+ acceptedByEmailController.text = value.employeeEmail ?? '';
+ setState(() {});
+ },
+ onChanged: (value) {},
+ ),
+ 8.height,
+ ] else ...[
+ AppTextFormField(
+ labelText: 'Accepted By'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: acceptedByController,
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onChange: (value) {
+ model.acceptedBy = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ ],
+ AppTextFormField(
+ labelText: 'Accepted By Email'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: acceptedByEmailController,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onChange: (value) {
+ model.acceptedByEmail = value;
+ },
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ enable: widget.isHmg == true ? false : true,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ ESignature(
+ title: 'End User Signature',
+ oldSignature: model.acceptedBySignature,
+ newSignature: newSignature,
+ backgroundColor: AppColor.neutral100,
+ showShadow: false,
+ onChange: (signature) {
+ updateSignature(signature: signature);
+ },
+ )
+ ],
+ );
+ }
+
+ void updateSignature({Uint8List? signature}) {
+ if (signature == null || signature.isEmpty) {
+ setState(() {
+ newSignature = null;
+ model.acceptedBySignature = null;
+ });
+ return;
+ }
+ setState(() {
+ newSignature = signature;
+ model.acceptedBySignature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
+ });
+ }
+
+ void _saveTap() async {
+ if (!_formKey.currentState!.validate()) {
+ return;
+ }
+ if (model.acceptanceDate == null) {
+ "Select Accepted date".showToast;
+ return;
+ }
+ if (widget.isHmg == true) {
+ if ((model.acceptedBy ?? '').isEmpty || (model.acceptedByEmail ?? '').isEmpty) {
+ 'Accepted By and Email are required'.addTranslation.showToast;
+ return;
+ }
+ }
+ if (model.acceptedBySignature == null || model.acceptedBySignature!.isEmpty) {
+ 'Signature is required'.addTranslation.showToast;
+ return;
+ }
+ _formKey.currentState!.save();
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ model.assetDeliveryExternalDetailId = widget.tableItemId;
+ await assetDeliveryProvider.saveEndUserFormData(model: model).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context, true);
+ }
+ });
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/history_log_view.dart b/lib/modules/asset_delivery_module/pages/history_log_view.dart
new file mode 100644
index 00000000..a5f6bf04
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/history_log_view.dart
@@ -0,0 +1,168 @@
+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/asset_delivery_module/models/history_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
+import 'package:test_sa/modules/cm_module/cm_request_utils.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class AssetDeliveryHistoryLogView extends StatefulWidget {
+ final int? tableItemId;
+ const AssetDeliveryHistoryLogView({Key? key,this.tableItemId}) : super(key: key);
+
+ @override
+ State createState() => _AssetDeliveryHistoryLogViewState();
+}
+
+
+
+
+class _AssetDeliveryHistoryLogViewState extends State {
+ List history = [];
+ @override
+ void initState() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+
+ void getInitialData() async {
+ history = await Provider.of(context, listen: false).getHistory(tableItemId: widget.tableItemId);
+ }
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Theme.of(context).scaffoldBackgroundColor,
+ // appBar: DefaultAppBar(
+ // title: 'History Log'.addTranslation,
+ // onBackPress: () {
+ // Navigator.pop(context);
+ // },
+ // ),
+ body: Consumer(builder: (context, provider, _) {
+ return provider.isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Stack(
+ children: [
+ Padding(
+ padding: EdgeInsets.only(left: 122.toScreenWidth),
+ child: const VerticalDivider(
+ color: AppColor.white40,
+ thickness: 2,
+ width: 20,
+ indent: 10,
+ endIndent: 10,
+ ),
+ ),
+ SafeArea(
+ child: Builder(builder: (cxt) {
+ List items = [];
+ String lastStatus = "";
+ DateTime? nextDate;
+ for (int i = 0; i < history.length; i++) {
+ var object = history[i];
+ String currentStatus = object.status!.name!;
+ if (lastStatus.isEmpty) {
+ lastStatus = currentStatus;
+ }
+ if (lastStatus == currentStatus) {
+ if (i + 1 < history.length) {
+ nextDate = history[i + 1].createdDate;
+ String timeDifference = CMRequestUtils.calculateTimeDifference(object.createdDate!, nextDate!);
+ object.timeDifference = timeDifference;
+ } else {
+ object.timeDifference = ''; // Empty string for the last action
+ }
+ items.add(historyLogCard(cxt, object));
+ } else {
+ items.add(statusCard(cxt, lastStatus));
+ lastStatus = currentStatus;
+ if (i + 1 < history.length) {
+ nextDate = history[i + 1].createdDate;
+ String timeDifference = CMRequestUtils.calculateTimeDifference(object.createdDate!, nextDate!);
+ object.timeDifference = timeDifference;
+ } else {
+ object.timeDifference = ''; // Empty string for the last action
+ }
+ items.add(historyLogCard(cxt, object));
+ }
+ }
+ items.add(statusCard(cxt, lastStatus));
+ return SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(children: items),
+ );
+ }),
+ ),
+ ],
+ );
+ }),
+ );}
+
+ Widget historyLogCard(BuildContext context, AssetDeliveryHistoryModel object) {
+ String title = object.status!.name!;
+
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Align(
+ alignment: Alignment.centerLeft,
+ child: Text(
+ object.createdDate.toString().toServiceRequestCardFormat,
+ textAlign: TextAlign.end,
+ style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ).expanded,
+ Expanded(
+ flex: 2,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ title.bodyText(context).custom(color: AppColor.textColor(context)),
+ // object.timeDifference.isNotEmpty ? object.timeDifference?.tinyFont(context).custom(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120) : const SizedBox(),
+ ],
+ ),
+ ),
+ ],
+ ).toShadowContainer(context, padding: 16).paddingOnly(bottom: 16);
+ }
+
+ Widget statusCard(BuildContext context, String status) {
+ return SizedBox(
+ width: 153.toScreenWidth,
+ child: StatusLabel(
+ radius: 4,
+ label: statusText(status.toLowerCase()),
+ labelInCenter: true,
+ textColor: AppColor.neutral50,
+ backgroundColor: AppColor.orange30,
+ ),
+ ).paddingOnly(bottom: 16, start: 40);
+ }
+// Need to check status text we have
+ String statusText(String status) {
+ if (status == "new" || status == "open") {
+ return "New".addTranslation;
+ } else if (status == "in progress") {
+ return "Status update to In Progress".addTranslation;
+ } else if (status == "closed") {
+ return "Status update to Closed".addTranslation;
+ } else if (status == "completed") {
+ return "Status update to Completed".addTranslation;
+ } else if (status == "fixed") {
+ return "Status update to Fixed".addTranslation;
+ } else if (status == "reject") {
+ return "Status update to Rejected".addTranslation;
+ } else
+ return status;
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart
new file mode 100644
index 00000000..4344c633
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart
@@ -0,0 +1,194 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/providers/api/devices_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/widget_extensions.dart';
+import 'package:test_sa/models/device/asset.dart';
+import 'package:test_sa/models/device/asset_search.dart';
+import 'package:test_sa/models/device/model_definition.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inpection_asset_model.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/custom_app_bar.dart';
+import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart';
+import 'package:test_sa/views/widgets/horizontal_list_widget.dart';
+import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+
+class TechnicalInspectionSearchAssetView extends StatefulWidget {
+ /// add on route
+ static const String id = "search_asset_view";
+ final int? lineId;
+
+ const TechnicalInspectionSearchAssetView({
+ Key? key,
+ this.lineId,
+ }) : super(key: key);
+
+ @override
+ State createState() => _TechnicalInspectionSearchAssetViewState();
+}
+
+class _TechnicalInspectionSearchAssetViewState extends State {
+ int _selectedIndex = 0;
+ DeviceSearch? search;
+ late TextEditingController _searchController;
+ late AssetProvider _deviceProvider;
+
+ //check for this list if not need remove
+ final List _searchableList = [];
+ final GlobalKey _formKey = GlobalKey();
+ bool _isFirst = true;
+
+ @override
+ void initState() {
+ _searchController = TextEditingController();
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ _searchController.dispose();
+ _deviceProvider.searchReset();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ List searchBy = [
+ context.translation.assetName,
+ context.translation.assetNumber,
+ 'model'.addTranslation,
+ 'manufacturer'.addTranslation,
+ // 'assetType'.addTranslation,
+ // 'assetOrigin'.addTranslation,
+ ];
+
+ _deviceProvider = Provider.of(context, listen: false);
+
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ appBar: CustomAppBar(
+ title: context.translation.searchAsset,
+ ),
+ body: Column(
+ children: [
+ HorizontalListWidget(
+ list: searchBy,
+ callBackFunction: (index) {
+ setState(() {
+ _selectedIndex = index;
+ });
+ },
+ ).paddingOnly(top: 16, bottom: 0),
+ Form(
+ key: _formKey,
+ child: AppTextFormField(
+ controller: _searchController,
+ textInputAction: TextInputAction.search,
+ labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
+ onAction: _search,
+ onChange: (text) {
+ _searchController.text = text;
+ _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
+ setState(() {});
+ },
+ onSaved: (value) {
+ setState(() {
+ search = DeviceSearch();
+ });
+ _setValue(value);
+ },
+ suffixIcon: IconButton(
+ icon: const Icon(Icons.search),
+ splashColor: Colors.transparent,
+ onPressed: _searchController.text.isNotEmpty ? _search : null,
+ color: AppColor.neutral20,
+ ).paddingOnly(end: 0),
+ ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8)),
+ Expanded(
+ child: _searchableList.isEmpty
+ ? _isFirst
+ ? const SizedBox()
+ : NoDataFound(message: context.translation.noDeviceFound)
+ : LazyLoading(
+ nextPage: _deviceProvider.nextPage,
+ onLazyLoad: () async {
+ if (_searchController.text.isNotEmpty) {
+ await _deviceProvider.getAssetsForAssetDelivery(search: search, lineId: widget.lineId, isSearchBy: true);
+ setState(() {
+ _searchableList.clear();
+ _searchableList.addAll(_deviceProvider.technicalInspectionAsset);
+ });
+ }
+ },
+ child: ListView.separated(
+ itemCount: _searchableList.length,
+ separatorBuilder: (listContext, itemIndex) => 8.height,
+ padding: const EdgeInsets.all(16),
+ itemBuilder: (listContext, itemIndex) {
+ return AssetItemListView(
+ device: Asset(
+ id: _searchableList[itemIndex].id,
+ assetNumber: _searchableList[itemIndex].assetNumber,
+ assetSerialNo: _searchableList[itemIndex].assetNumber,
+ modelDefinition: ModelDefinition(assetName: _searchableList[itemIndex].assetName, modelName: _searchableList[itemIndex].model),
+ ),
+ onPressed: (device) {
+ Navigator.of(context).pop(device);
+ },
+ );
+ },
+ ),
+ ),
+ )
+ ],
+ ));
+ }
+
+ void _search({bool loadMore = false}) async {
+ FocusScope.of(context).unfocus();
+ _formKey.currentState?.save();
+ _searchableList.clear();
+ _deviceProvider.technicalInspectionAsset.clear();
+ setState(() {});
+ _deviceProvider.searchReset();
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await _deviceProvider.getAssetsForAssetDelivery(
+ search: search,
+ lineId: widget.lineId,
+ isSearchBy: true,
+ );
+
+ setState(() {
+ _searchableList.clear();
+ _searchableList.addAll(_deviceProvider.technicalInspectionAsset);
+ _isFirst = false;
+ });
+
+ Navigator.pop(context);
+ }
+
+ _setValue(String? value) {
+ search ??= DeviceSearch();
+ switch (_selectedIndex) {
+ case 0:
+ search!.assetName = value;
+ break;
+ case 1:
+ search!.assetNo = value;
+ break;
+ case 2:
+ search!.model = value;
+ break;
+ case 3:
+ search!.manufacturer = value;
+ break;
+ }
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart
new file mode 100644
index 00000000..e98c1213
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart
@@ -0,0 +1,215 @@
+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/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.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/default_app_bar.dart';
+
+class InspectionCheckListView extends StatefulWidget {
+ final List? initialValues;
+
+ const InspectionCheckListView({super.key, this.initialValues});
+
+ @override
+ State createState() => _InspectionCheckListViewState();
+}
+
+class _InspectionCheckListViewState extends State {
+ late List checklist;
+
+ @override
+ void initState() {
+ super.initState();
+ checklist = AssetDeliveryUtils.inspectionChecklist.map((e) => InspectionChecklistItem(title: e.title)).toList();
+
+ if (widget.initialValues != null && widget.initialValues!.isNotEmpty) {
+ for (final item in checklist) {
+ final matched = widget.initialValues!.firstWhere(
+ (e) => e.title == item.title,
+ orElse: () => InspectionChecklistItem(),
+ );
+ item.status = matched.status; // null-safe
+ }
+ }
+ }
+
+ void updateStatus(int index, String value) {
+ setState(() {
+ checklist[index].status = value;
+ });
+ }
+
+ List get selectedValues => checklist.where((e) => e.status != null).toList();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: DefaultAppBar(
+ title: 'Asset Check List'.addTranslation,
+ ),
+ body: Column(
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: List.generate(
+ checklist.length,
+ (index) {
+ final model = checklist[index];
+ return inspectionStatusRadioWidget(
+ model: model,
+ index: index,
+ context: context,
+ );
+ },
+ ),
+ ).toShadowContainer(
+ context,
+ borderRadius: 20,
+ margin: const EdgeInsets.only(top: 12, left: 12, right: 12),
+ ),
+ const Spacer(),
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: 'Save'.addTranslation,
+ maxWidth: true,
+ onPressed: () {
+ Navigator.pop(context, selectedValues);
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget inspectionStatusRadioWidget({required int index, required InspectionChecklistItem model, required BuildContext context}) {
+ bool status = (model.status == null || model.status == null) ? true : (model.status != null ? (model.status == 'true' ? true : false) : false);
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ model.title ?? '',
+ overflow: TextOverflow.ellipsis,
+ maxLines: 1,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? Colors.white : AppColor.white936),
+ ),
+ 14.height,
+ // Column(
+ // crossAxisAlignment: CrossAxisAlignment.start,
+ // children: [
+ //
+ // (status ? 'Pass' : 'Fail').bodyText2(context).custom(color: AppColor.neutral120, fontWeight: FontWeight.w500),
+ // ],
+ // ).expanded,
+ GestureDetector(
+ onTap: () {
+ setState(() {
+ status = !status;
+ model.status = status.toString();
+ });
+ },
+ child: Container(
+ width: 99.toScreenWidth,
+ height: 40.toScreenHeight,
+ padding: EdgeInsetsDirectional.all(4.toScreenHeight),
+ decoration: BoxDecoration(
+ color: AppColor.fieldBgColor(context),
+ borderRadius: BorderRadius.circular(5),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ buildToggleOption(
+ label: "PASS",
+ isActive: status,
+ activeColor: AppColor.green20,
+ inactiveColor: Colors.transparent,
+ textColor: status
+ ? AppColor.green50
+ : context.isDark
+ ? Colors.white
+ : AppColor.black20,
+ ),
+ buildToggleOption(
+ label: "FAIL",
+ isActive: !status,
+ activeColor: AppColor.red20,
+ inactiveColor: Colors.transparent,
+ textColor: status
+ ? context.isDark
+ ? Colors.white
+ : AppColor.black20
+ : AppColor.red30,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ).paddingOnly(top: 4, bottom: 4);
+ }
+
+ Widget buildToggleOption({
+ required String label,
+ required bool isActive,
+ required Color activeColor,
+ required Color inactiveColor,
+ required Color textColor,
+ }) {
+ return Container(
+ width: 44.toScreenWidth,
+ height: 30.toScreenHeight,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ color: isActive ? activeColor : inactiveColor,
+ borderRadius: BorderRadius.circular(3),
+ ),
+ child: label.bodyText2(context).custom(color: textColor),
+ );
+ }
+
+//older widget ...
+// return Column(
+// crossAxisAlignment: CrossAxisAlignment.start,
+// children: [
+// Text(
+// item.title ?? '',
+// style: AppTextStyles.heading6.copyWith(
+// color: context.isDark ? AppColor.neutral30 : AppColor.black10,
+// ),
+// ),
+// Row(
+// children: [
+// Expanded(
+// child: RadioListTile(
+// title: const Text('Pass'),
+// value: 'PASS',
+// groupValue: item.status,
+// onChanged: (v) => updateStatus(index, v!),
+// ),
+// ),
+// Expanded(
+// child: RadioListTile(
+// title: const Text('Fail'),
+// value: 'FAIL',
+// groupValue: item.status,
+// onChanged: (v) => updateStatus(index, v!),
+// ),
+// ),
+// ],
+// ),
+// ],
+// );
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart
new file mode 100644
index 00000000..b09eb878
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart
@@ -0,0 +1,138 @@
+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/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class TechnicalInspectionAssetCard extends StatelessWidget {
+ TechnicalInspectionAssetModel assetModel;
+ bool isViewOnly;
+ bool ischild;
+ VoidCallback? editPress;
+
+ TechnicalInspectionAssetCard({
+ super.key,
+ required this.isViewOnly,
+ this.ischild = false,
+ required this.assetModel,
+ this.editPress,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (!ischild) ...[
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ StatusLabel(
+ label: getAssetStatus(),
+ radius: 4,
+ textColor: getAssetStatusColor(context: context, status: getAssetStatus(), isBackground: false),
+ backgroundColor: getAssetStatusColor(context: context, status: getAssetStatus()),
+ ),
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset().onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ 8.height,
+ ],
+ if (ischild) ...[
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ 'Asset Number: ${assetModel.assetNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset().onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ 2.height,
+ ],
+ Text(
+ 'Asset Name: ${assetModel.modelDefinition?.assetName ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ if (!ischild)
+ Text(
+ 'Asset Number: ${assetModel.assetNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Model: ${assetModel.modelDefinition?.model ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Manufacturer: ${assetModel.modelDefinition?.manufacturer ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Serial Number: ${assetModel.serialNo ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'System ID: ${assetModel.systemId ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Medical Department: ${assetModel.department?.name ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Installation Date: ${assetModel.installationDate ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ 'Asset Type: ${assetModel.assetType?.name ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+
+ Color getAssetStatusColor({required BuildContext context, required String status, bool? isBackground = true}) {
+ switch (status) {
+ case 'PASS':
+ return isBackground! ? AppColor.green70.withOpacity(0.4) : AppColor.green15;
+ case 'FAIL':
+ return isBackground! ? AppColor.red30.withOpacity(0.4) : AppColor.red30;
+ default:
+ return Colors.white10;
+ }
+ }
+
+ String getAssetStatus() {
+ final flags = [
+ assetModel.flagphysicalInspection,
+ assetModel.flagFunctionPerformance,
+ assetModel.flagGroundingResistance,
+ assetModel.flagChassiss,
+ assetModel.flagLeadsLeakage,
+ assetModel.flagAlert,
+ ];
+ if (flags.any((f) => f == false)) {
+ return 'FAIL';
+ }
+ if (flags.every((f) => f == true)) {
+ return 'PASS';
+ }
+ return 'FAIL';
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart
new file mode 100644
index 00000000..c9488779
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart
@@ -0,0 +1,58 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:test_sa/common_widgets/lookup_autocomplete_field.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/asset_delivery_module/models/cost_center_model.dart';
+import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+
+class TechnicalInspectionCostCard extends StatelessWidget {
+ CostCenterModel costModel;
+ VoidCallback? editPress;
+ bool isViewOnly;
+
+ TechnicalInspectionCostCard({
+ super.key,
+ required this.costModel,
+ this.editPress,
+ required this.isViewOnly,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ //need to check this @waseem.
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: Text(
+ 'Cost Center Name: ${costModel.costCenterName ?? '-'}',
+ overflow: TextOverflow.ellipsis,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ),
+ 8.width,
+ if (!isViewOnly)
+ 'edit_icon'.toSvgAsset(height: 18, width: 18).onPress(() {
+ if (editPress != null) {
+ editPress!();
+ }
+ }),
+ ],
+ ),
+ Text(
+ 'Quantity: ${costModel.quantity ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12);
+ }
+}
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
new file mode 100644
index 00000000..e2c05093
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart
@@ -0,0 +1,284 @@
+import 'dart:developer';
+
+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/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';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_stage_tab_page.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.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/update_technical_inspection_lines_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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/single_item_drop_down_menu.dart';
+import 'package:test_sa/providers/service_request_providers/last_situation_provider.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';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class TechnicalInspectionLinesListView extends StatefulWidget {
+ final AssetDeliveryTableModel deliveryTableModel;
+ final AssetDeliveryDataModel? requestModel;
+
+ TechnicalInspectionLinesListView({
+ Key? key,
+ required this.deliveryTableModel,
+ this.requestModel,
+ }) : super(key: key);
+
+ @override
+ State createState() => _TechnicalInspectionLinesListViewState();
+}
+
+class _TechnicalInspectionLinesListViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ bool viewOnly = false;
+ bool isLoading = false;
+ AssetDeliveryProvider? assetDeliveryProvider;
+ List technicalInspectionLinesList = [];
+
+ @override
+ void initState() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ void getInitialData() async {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ viewOnly = widget.deliveryTableModel.status?.value != 3;
+ isLoading = true;
+ setState(() {});
+ technicalInspectionLinesList = await assetDeliveryProvider!.getTechnicalInspectionLinesListById(
+ //TODO uncommit this after testing @waseem
+ itemId: widget.deliveryTableModel.id,
+ // itemId: 2,
+ );
+ isLoading = false;
+ setState(() {});
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ // appBar: DefaultAppBar(
+ // title: 'Technical Inspection'.addTranslation,
+ // titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ // ),
+ body: Form(
+ key: _formKey,
+ child: (isLoading)
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : (technicalInspectionLinesList.isEmpty)
+ ? const NoDataFound().center
+ : Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ children: [
+ ListView.separated(
+ padding: const EdgeInsets.all(0),
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemCount: technicalInspectionLinesList.length + 1,
+ // +1 for the header
+ separatorBuilder: (_, __) => 8.height,
+ itemBuilder: (context, index) {
+ if (index == 0) {
+ return Text(
+ "Lines",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ );
+ }
+
+ final DeliveryLineModel model = technicalInspectionLinesList[index - 1];
+ return AssetDeliveryLineCard(
+ deliveryLineModel: model,
+ isViewOnly: viewOnly,
+ isTechnical: true,
+ editPress: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UpdateTechnicalInspectionLinesView(
+ requestModel: widget.requestModel,
+ deliveryTableModel: widget.deliveryTableModel,
+ deliveryLineModel: model,
+ ),
+ ),
+ );
+ },
+ );
+ },
+ ).toShadowContainer(context, borderRadius: 20, padding: 12),
+ ],
+ ),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: !viewOnly
+ ? Column(
+ children: [
+ AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
+ 16.height,
+ Row(
+ children: [
+ AppFilledButton(
+ label: 'Cancel'.addTranslation,
+ maxWidth: true,
+ buttonColor: AppColor.background(context),
+ // textColor: context.isDark ? AppColor.neutral30 : Colors.white,
+ textColor: AppColor.red30,
+ showBorder: true,
+ onPressed: _cancelTap,
+ ).expanded,
+ 12.width,
+ AppFilledButton(buttonColor: AppColor.green70, label: 'Change Status'.addTranslation, maxWidth: true, onPressed: _changeStatusTap).expanded,
+ ],
+ ),
+ ],
+ )
+ : Row(
+ children: [
+ AppFilledButton(
+ buttonColor: AppColor.white60,
+ label: 'Attachments'.addTranslation,
+ maxWidth: true,
+ textColor: AppColor.black10,
+ onPressed: () {
+ HelperFunction.attachmentTap(
+ context: context, viewOnly: true, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ }).expanded,
+ 8.width,
+ AppFilledButton(buttonColor: AppColor.primary10, label: 'Next'.addTranslation, maxWidth: true, onPressed: _nextTap).expanded,
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+//May be need to show data.
+ Widget inspectionDetails() {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'Inspected by'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ 'Mahmoud Shrouf'.addTranslation,
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Approved by'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ 'Mahmoud Shrouf'.addTranslation,
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Inspected Date/Time From'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ '19 August, 2025'.addTranslation,
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ 8.height,
+ Text(
+ 'Inspected Date/Time To'.addTranslation,
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ Text(
+ '19 August, 2025'.addTranslation,
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ],
+ );
+ }
+
+ void _changeStatusTap() async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider?.changeDeliveryStatus(itemId: widget.deliveryTableModel.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ void _attachmentTap() async {
+ HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => AssetDeliveryAttachmentView(
+ // tableItemId: widget.deliveryTableModel.id,
+ // )));
+ }
+
+ void _cancelTap() async {
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider?.changeDeliveryStatusToCancel(itemId: widget.deliveryTableModel.id).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ await assetDeliveryProvider?.getAssetDeliveryTableListById(requestId: widget.requestModel?.id);
+ }
+ });
+ }
+
+ void _nextTap() async {
+ // Navigator.push(
+ // context,
+ // MaterialPageRoute(
+ // builder: (context) => EndUserCostCenterLIstView(
+ // requestModel: widget.requestModel,
+ // deliveryTableModel: widget.deliveryTableModel,
+ // )));
+
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => AssetDeliveryStageTabPage(
+ title: 'End-User Acceptance'.addTranslation,
+ detailWidget: EndUserCostCenterLIstView(
+ deliveryTableModel: widget.deliveryTableModel,
+ requestModel: widget.requestModel,
+ ),
+ tableId: widget.deliveryTableModel.id,
+ )));
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart
new file mode 100644
index 00000000..5f6a60c6
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_list_view.dart
@@ -0,0 +1,133 @@
+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/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class TechnicalInspectionParentAssetListView extends StatefulWidget {
+ final int? costCenterId;
+ final int? tableItemId;
+ final int? lineId;
+
+ TechnicalInspectionParentAssetListView({
+ Key? key,
+ this.costCenterId,
+ this.tableItemId,
+ this.lineId,
+ }) : super(key: key);
+
+ @override
+ State createState() => _TechnicalInspectionParentAssetListViewState();
+}
+
+class _TechnicalInspectionParentAssetListViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ bool viewOnly = false;
+ AssetDeliveryProvider? assetDeliveryProvider;
+ List assetList = [];
+ bool isLoading = false;
+
+ @override
+ void initState() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ void getInitialData() async {
+ setState(() {
+ isLoading = true;
+ });
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ //TODO replace static id's after testing...
+ assetList = await assetDeliveryProvider!.getParentAssetList(
+ costCenterId: widget.costCenterId,
+ tableItemId: widget.tableItemId,
+ lineId: widget.lineId,
+ );
+
+ setState(() {
+ isLoading = false;
+ });
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(
+ title: 'Technical Inspection'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ body:Form(
+ key: _formKey,
+ child: parentAssetList(context), // parentAssetList already returns a ListView
+ ),
+ );
+ }
+
+ Widget parentAssetList(BuildContext context) {
+ if (isLoading) {
+ return SizedBox.expand(
+ child: const CircularProgressIndicator(color: AppColor.primary10).center,
+ );
+ }
+
+ if (assetList.isEmpty) {
+ return const NoDataFound().center;
+ }
+
+ return ListView.separated(
+ padding: const EdgeInsets.all(16),
+ itemCount: assetList.length + 1, // +1 for the "Parents" header
+ separatorBuilder: (_, __) => 8.height,
+ itemBuilder: (context, index) {
+ if (index == 0) {
+ return Text(
+ "Parents",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ );
+ }
+
+ final asset = assetList[index - 1];
+ return TechnicalInspectionAssetCard(
+ assetModel: asset,
+ isViewOnly: viewOnly,
+ editPress: () async {
+ bool isRefreshed = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UpdateParentAssetView(
+ assetModel: asset,
+ lineId: widget.lineId,
+ tableItemId: widget.tableItemId,
+ costCenterItemId: widget.costCenterId,
+ ),
+ ),
+ );
+
+ if (isRefreshed) {
+ getInitialData();
+ }
+ },
+ );
+ },
+ );
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart
new file mode 100644
index 00000000..bdbec424
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart
@@ -0,0 +1,472 @@
+import 'dart:developer';
+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/new_models/building.dart';
+import 'package:test_sa/models/new_models/floor.dart';
+import 'package:test_sa/models/new_models/site.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
+import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
+import 'package:test_sa/providers/loading_list_notifier.dart';
+import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
+import '../../../../models/new_models/department.dart';
+import '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class UpdateChildAssetView extends StatefulWidget {
+ final TechnicalInspectionAssetModel assetModel;
+ final int? lineId;
+ final int index;
+
+ UpdateChildAssetView({
+ Key? key,
+ required this.assetModel,
+ required this.index,
+ this.lineId,
+ }) : super(key: key);
+
+ @override
+ State createState() => _UpdateChildAssetViewState();
+}
+
+class _UpdateChildAssetViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ List checkList = [];
+ late SiteProvider siteProvider;
+ late AssetDeliveryProvider assetDeliveryProvider;
+ late TextEditingController assetNumberCtrl;
+ late TextEditingController serialNoCtrl;
+ late TextEditingController systemIdCtrl;
+
+ @override
+ void initState() {
+ siteProvider = Provider.of(context, listen: false);
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ assetNumberCtrl = TextEditingController();
+ serialNoCtrl = TextEditingController();
+ systemIdCtrl = TextEditingController();
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ populateForm();
+ });
+ super.initState();
+ }
+
+ void populateForm() async {
+ assetDeliveryProvider.isChildAssetDataLoading = true;
+ assetDeliveryProvider.setChildModel(widget.assetModel);
+ if (widget.assetModel.site != null) {
+ await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: assetDeliveryProvider.childFormModel);
+ }
+ populateTextFields(model: assetDeliveryProvider.childFormModel);
+ assetDeliveryProvider.isChildAssetDataLoading = false;
+ }
+
+ void populateTextFields({required TechnicalInspectionAssetModel model}) {
+ assetNumberCtrl.text = model.assetNumber ?? '';
+ serialNoCtrl.text = model.serialNo ?? '';
+ systemIdCtrl.text = model.systemId ?? '';
+ setState(() {});
+ }
+
+ @override
+ void dispose() {
+ assetNumberCtrl.dispose();
+ serialNoCtrl.dispose();
+ systemIdCtrl.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(
+ title: 'Child Details'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ body: Form(
+ key: _formKey,
+ child: Consumer(builder: (context, provider, child) {
+ return provider.isChildAssetDataLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ inspectionDetailsForm(
+ lineId: widget.lineId,
+ provider: provider,
+ ),
+ 8.height,
+ const Divider().defaultStyle(context),
+ 8.height,
+ testLines(
+ context: context,
+ )
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12))
+ .expanded,
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
+ ],
+ );
+ }),
+ ),
+ );
+ }
+
+ Widget testLines({required BuildContext context}) {
+ return Row(
+ children: [
+ Text(
+ "Test List",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.width,
+ 'web_link_icon'.toSvgAsset().onPress(() {
+ openInspectionChecklist(context);
+ }),
+ ],
+ );
+ }
+
+ /// Need to make reuseable as used in parent and child both.
+
+ Widget inspectionDetailsForm({
+ int? lineId,
+ required AssetDeliveryProvider provider,
+ }) {
+ TechnicalInspectionAssetModel model = provider.childFormModel;
+ return Column(
+ children: [
+ AppTextFormField(
+ labelText: 'Asset Number'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: assetNumberCtrl,
+ initialValue: model.assetNumber,
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ enable: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ).onPress(() async {
+ var data = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => TechnicalInspectionSearchAssetView(
+ lineId: lineId,
+ )));
+ if (data != null) {
+ TechnicalInspectionAssetModel? assetModel = await provider.getAssetDetails(assetId: data?.id);
+
+ if (assetModel != null) {
+ provider.setChildModel(assetModel);
+ if (assetModel.site != null) {
+ await provider.getSiteData(siteId: assetModel.site?.id, model: provider.childFormModel);
+ }
+ provider.setParentModel(assetModel);
+ populateTextFields(model: provider.childFormModel);
+ }
+ }
+ }),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Asset Name'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.assetName,
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Model'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.model,
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Manufacturer'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.manufacturer ?? '',
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Serial Number'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: serialNoCtrl,
+ initialValue: model.serialNo ?? '',
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ onSaved: (value) {
+ model.serialNo = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'System ID'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: systemIdCtrl,
+ initialValue: model.systemId ?? '',
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ onSaved: (value) {
+ model.systemId = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Site',
+ initialValue: model.site,
+ loading: provider.isSiteLoading,
+ showAsBottomSheet: true,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showShadow: false,
+ // enabled: false,
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.site = value;
+ model.building = null;
+ model.floor = null;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Building',
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ loading: provider.isSiteLoading,
+ showShadow: false,
+ initialValue: model.building,
+ enabled: model.site?.buildings?.isNotEmpty ?? false,
+ staticData: model.site?.buildings ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.building = value;
+ model.floor = null;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ showAsBottomSheet: true,
+ backgroundColor: AppColor.fieldBgColor(context),
+ loading: provider.isSiteLoading,
+ showShadow: false,
+ title: 'Floor',
+ initialValue: model.floor,
+ enabled: model.building?.floors?.isNotEmpty ?? false,
+ staticData: model.building?.floors ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.floor = value;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Department',
+ backgroundColor: AppColor.fieldBgColor(context),
+ loading: provider.isSiteLoading,
+ showAsBottomSheet: true,
+ showShadow: false,
+ initialValue: model.department,
+ enabled: model.floor?.departments?.isNotEmpty ?? false,
+ staticData: model.floor?.departments ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.department = value;
+ model.room = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ ADatePicker(
+ label: 'Installation Date'.addTranslation,
+ hideShadow: true,
+ height: 56.toScreenHeight,
+ backgroundColor: AppColor.fieldBgColor(context),
+ date: model.installationDate,
+ // from: widget.pickerFromDate,
+ formatDateWithTime: true,
+ onDatePicker: (selectedDate) {
+ showTimePicker(
+ context: context,
+ initialTime: TimeOfDay.now(),
+ builder: (BuildContext context, Widget? child) {
+ final ThemeData currentTheme = Theme.of(context);
+ return Theme(
+ data: currentTheme.copyWith(
+ timePickerTheme: TimePickerThemeData(
+ dialHandColor: AppColor.primary10,
+ dialBackgroundColor: Colors.grey.withOpacity(0.1),
+ hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
+ dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
+ dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
+ dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
+ entryModeIconColor: AppColor.primary10,
+ ),
+ textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
+ ),
+ child: child!,
+ );
+ },
+ ).then((selectedTime) {
+ if (selectedTime != null) {
+ model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
+ setState(() {});
+ }
+ });
+ },
+ ),
+ 8.height,
+ ],
+ );
+ }
+
+ ///Need to check which details show here...
+
+ void _saveTap() async {
+ if (!_formKey.currentState!.validate()) return;
+ if (assetDeliveryProvider.childFormModel.installationDate == null) {
+ "Installation Date is Required".showToast;
+ return;
+ }
+ _formKey.currentState!.save();
+
+ //Need to check if not auto update.
+ // assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel;
+ Navigator.pop(context);
+ }
+
+ Future openInspectionChecklist(BuildContext context) async {
+ applyInspectionFlagsToChecklist(model: assetDeliveryProvider.childFormModel);
+
+ final result = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => InspectionCheckListView(
+ initialValues: checkList,
+ )));
+ if (result != null) {
+ checkList = result;
+ setState(() {});
+ }
+ buildInspectionPayload(checkList);
+ }
+
+ bool _isPass(List list, String title) {
+ return list
+ .firstWhere(
+ (e) => e.title == title,
+ orElse: () => InspectionChecklistItem(status: 'FAIL'),
+ )
+ .status ==
+ 'PASS';
+ }
+
+ buildInspectionPayload(List checklist) {
+ assetDeliveryProvider.childFormModel.flagphysicalInspection = _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions');
+ assetDeliveryProvider.childFormModel.flagFunctionPerformance = _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List');
+ assetDeliveryProvider.childFormModel.flagGroundingResistance = _isPass(checklist, 'Grounding Resistance: Ω');
+ assetDeliveryProvider.childFormModel.flagChassiss = _isPass(checklist, 'Chassis Leakage Current: µA');
+ assetDeliveryProvider.childFormModel.flagLeadsLeakage = _isPass(checklist, 'Leads Leakage Current: µA');
+ assetDeliveryProvider.childFormModel.flagAlert = _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form');
+ }
+
+ void applyInspectionFlagsToChecklist({
+ required TechnicalInspectionAssetModel model,
+ }) {
+ if (checkList.isEmpty) {
+ checkList = AssetDeliveryUtils.inspectionChecklist;
+ }
+ for (final item in checkList) {
+ switch (item.value) {
+ case 'flagphysicalInspection':
+ item.status = _statusFromBool(model.flagphysicalInspection);
+ break;
+
+ case 'flagFunctionPerformance':
+ item.status = _statusFromBool(model.flagFunctionPerformance);
+ break;
+
+ case 'flagGroundingResistance':
+ item.status = _statusFromBool(model.flagGroundingResistance);
+ break;
+
+ case 'flagChassiss':
+ item.status = _statusFromBool(model.flagChassiss);
+ break;
+
+ case 'flagLeadsLeakage':
+ item.status = _statusFromBool(model.flagLeadsLeakage);
+ break;
+
+ case 'flagAlert':
+ item.status = _statusFromBool(model.flagAlert);
+ break;
+ }
+ }
+ }
+
+ String _statusFromBool(bool? value) {
+ return value == true
+ ? 'PASS'
+ : value == false
+ ? 'FAIL'
+ : '';
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart
new file mode 100644
index 00000000..ceafcfe6
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart
@@ -0,0 +1,521 @@
+import 'dart:developer';
+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/new_models/building.dart';
+import 'package:test_sa/models/new_models/floor.dart';
+import 'package:test_sa/models/new_models/site.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_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/single_item_drop_down_menu.dart';
+import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
+import 'package:test_sa/providers/loading_list_notifier.dart';
+import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
+import '../../../../models/new_models/department.dart';
+import '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class UpdateParentAssetView extends StatefulWidget {
+ final TechnicalInspectionAssetModel assetModel;
+ final int? lineId;
+ final int? tableItemId;
+ final int? costCenterItemId;
+
+ UpdateParentAssetView({
+ Key? key,
+ required this.assetModel,
+ this.lineId,
+ this.tableItemId,
+ this.costCenterItemId,
+ }) : super(key: key);
+
+ @override
+ State createState() => _UpdateParentAssetViewState();
+}
+
+class _UpdateParentAssetViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ List checkList = [];
+ late SiteProvider siteProvider;
+ late AssetDeliveryProvider assetDeliveryProvider;
+ late TextEditingController assetNumberCtrl;
+ late TextEditingController serialNoCtrl;
+ late TextEditingController systemIdCtrl;
+
+ @override
+ void initState() {
+ siteProvider = Provider.of(context, listen: false);
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ assetNumberCtrl = TextEditingController();
+ serialNoCtrl = TextEditingController();
+ systemIdCtrl = TextEditingController();
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ populateForm();
+ });
+ super.initState();
+ }
+
+ void populateForm() async {
+ assetDeliveryProvider.isLoading = true;
+ assetDeliveryProvider.setParentModel(widget.assetModel);
+ if (widget.assetModel.site != null) {
+ await assetDeliveryProvider.getSiteData(siteId: widget.assetModel.site?.id, model: assetDeliveryProvider.parentFormModel);
+ } else {
+ if (siteProvider.items.isEmpty) {
+ await siteProvider.getData();
+ }
+ }
+ populateTextFields(model: assetDeliveryProvider.parentFormModel);
+ assetDeliveryProvider.isLoading = false;
+ }
+
+ void populateTextFields({required TechnicalInspectionAssetModel model}) {
+ assetNumberCtrl.text = model.assetNumber ?? '';
+ serialNoCtrl.text = model.serialNo ?? '';
+ systemIdCtrl.text = model.systemId ?? '';
+ setState(() {});
+ }
+
+ @override
+ void dispose() {
+ assetNumberCtrl.dispose();
+ serialNoCtrl.dispose();
+ systemIdCtrl.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(
+ title: 'Parent Details'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ body: Form(
+ key: _formKey,
+ child: Consumer(builder: (context, provider, child) {
+ return provider.isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ inspectionDetailsForm(lineId: widget.lineId, provider: provider),
+ 8.height,
+ const Divider().defaultStyle(context),
+ 8.height,
+ Row(
+ children: [
+ Text(
+ "Test List",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.width,
+ 'web_link_icon'.toSvgAsset().onPress(() {
+ openInspectionChecklist(context);
+ }),
+ ],
+ ),
+ 8.height,
+ childList(
+ context: context,
+ provider: provider,
+ )
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12))
+ .expanded,
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
+ ],
+ );
+ }),
+ ),
+ );
+ }
+
+ Widget childList({required BuildContext context, required AssetDeliveryProvider provider}) {
+ final List assetDeliveryTableList = provider.parentFormModel.childAssetList ?? [];
+ return ListView.separated(
+ itemCount: assetDeliveryTableList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ TechnicalInspectionAssetModel model = assetDeliveryTableList[itemIndex];
+ return TechnicalInspectionAssetCard(
+ assetModel: model,
+ ischild: true,
+ editPress: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => UpdateChildAssetView(
+ assetModel: model,
+ index: itemIndex,
+ )));
+ },
+ isViewOnly: false,
+ );
+ },
+ );
+ }
+
+ /// Need to make reuseable as used in parent and child both.
+
+ Widget inspectionDetailsForm({
+ int? lineId,
+ required AssetDeliveryProvider provider,
+ }) {
+ TechnicalInspectionAssetModel model = provider.parentFormModel;
+ return Column(
+ children: [
+ //Replace with simple container...
+ AppTextFormField(
+ labelText: 'Asset Number'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: assetNumberCtrl,
+ initialValue: model.assetNumber,
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ enable: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ).onPress(() async {
+ var data = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => TechnicalInspectionSearchAssetView(
+ lineId: lineId,
+ )));
+ if (data != null) {
+ TechnicalInspectionAssetModel? assetModel = await provider.getAssetDetails(assetId: data?.id);
+
+ if (assetModel != null) {
+ provider.setParentModel(assetModel);
+ if (assetModel.site != null) {
+ await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel);
+ }
+ assetModel.assetDeliveryInternalDetailAssetId = assetModel.id;
+ assetModel.id = 0;
+ if (assetModel.childAssetList != null && assetModel.childAssetList!.isNotEmpty) {
+ for (var asset in assetModel.childAssetList!) {
+ asset.assetDeliveryInternalDetailAssetChildId = asset.id;
+ asset.id = 0;
+ }
+ }
+ provider.setParentModel(assetModel);
+ log('child list length ${assetModel.childAssetList?.length}');
+
+ populateTextFields(model: provider.parentFormModel);
+ }
+ }
+ }),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Asset Name'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.assetName,
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Model'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.model,
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Manufacturer'.addTranslation,
+ // backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.modelDefinition?.manufacturer ?? '',
+ textAlign: TextAlign.center,
+ enable: false,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Serial Number'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: serialNoCtrl,
+ initialValue: model.serialNo ?? '',
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ onSaved: (value) {
+ model.serialNo = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'System ID'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ controller: systemIdCtrl,
+ initialValue: model.systemId ?? '',
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ onSaved: (value) {
+ model.systemId = value;
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Site',
+ initialValue: model.site,
+ loading: provider.isSiteLoading,
+ showAsBottomSheet: true,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showShadow: false,
+ // enabled: false,
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.site = value;
+ model.building = null;
+ model.floor = null;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Building',
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ loading: provider.isSiteLoading,
+ showShadow: false,
+ initialValue: model.building,
+ enabled: model.site?.buildings?.isNotEmpty ?? false,
+ staticData: model.site?.buildings ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.building = value;
+ model.floor = null;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ showAsBottomSheet: true,
+ backgroundColor: AppColor.fieldBgColor(context),
+ loading: provider.isSiteLoading,
+ showShadow: false,
+ title: 'Floor',
+ initialValue: model.floor,
+ enabled: model.building?.floors?.isNotEmpty ?? false,
+ staticData: model.building?.floors ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.floor = value;
+ model.department = null;
+ setState(() {});
+ },
+ ),
+ 8.height,
+ SingleItemDropDownMenu(
+ context: context,
+ title: 'Department',
+ backgroundColor: AppColor.fieldBgColor(context),
+ loading: provider.isSiteLoading,
+ showAsBottomSheet: true,
+ showShadow: false,
+ initialValue: model.department,
+ enabled: model.floor?.departments?.isNotEmpty ?? false,
+ staticData: model.floor?.departments ?? [],
+ onSelect: (value) {
+ if (value == null) {
+ return;
+ }
+ model.department = value;
+ model.room = null;
+ setState(() {});
+ },
+ ),
+
+ 8.height,
+ ADatePicker(
+ label: 'Installation Date'.addTranslation,
+ hideShadow: true,
+ height: 56.toScreenHeight,
+ backgroundColor: AppColor.fieldBgColor(context),
+ date: model.installationDate,
+ //Need to check whare the picker start for now start from start of year
+ from: DateTime(DateTime.now().year, 1, 1),
+ formatDateWithTime: true,
+ onDatePicker: (selectedDate) {
+ showTimePicker(
+ context: context,
+ initialTime: TimeOfDay.now(),
+ builder: (BuildContext context, Widget? child) {
+ final ThemeData currentTheme = Theme.of(context);
+ return Theme(
+ data: currentTheme.copyWith(
+ timePickerTheme: TimePickerThemeData(
+ dialHandColor: AppColor.primary10,
+ dialBackgroundColor: Colors.grey.withOpacity(0.1),
+ hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
+ dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
+ dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
+ dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
+ entryModeIconColor: AppColor.primary10,
+ ),
+ textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
+ ),
+ child: child!,
+ );
+ },
+ ).then((selectedTime) {
+ if (selectedTime != null) {
+ model.installationDate = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
+ setState(() {});
+ }
+ });
+ },
+ ),
+ 8.height,
+ ],
+ );
+ }
+
+ ///Need to check which details show here...
+
+ void _saveTap() async {
+ if (!_formKey.currentState!.validate()) return;
+ if (assetDeliveryProvider.parentFormModel.installationDate == null) {
+ "Installation Date is Required".showToast;
+ return;
+ }
+ _formKey.currentState!.save();
+ assetDeliveryProvider.parentFormModel.lineId = widget.lineId;
+
+ assetDeliveryProvider.parentFormModel.tableItemId = widget.tableItemId;
+ assetDeliveryProvider.parentFormModel.costCenterId = widget.costCenterItemId;
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider.saveTechnicalInspectionAssetData(model: assetDeliveryProvider.parentFormModel).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context, true);
+ }
+ });
+ }
+
+ Future openInspectionChecklist(BuildContext context) async {
+ applyInspectionFlagsToChecklist(model: assetDeliveryProvider.parentFormModel);
+ final result = await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => InspectionCheckListView(
+ initialValues: checkList,
+ )));
+
+ if (result != null) {
+ checkList = result;
+ setState(() {});
+ }
+ buildInspectionPayload(checkList);
+ }
+
+ bool _isPass(List list, String title) {
+ return list
+ .firstWhere(
+ (e) => e.title == title,
+ orElse: () => InspectionChecklistItem(status: 'FAIL'),
+ )
+ .status ==
+ 'PASS';
+ }
+
+ buildInspectionPayload(List checklist) {
+ assetDeliveryProvider.parentFormModel.flagphysicalInspection = _isPass(checklist, 'Physical Inspection As Per Manufacturer Instructions');
+ assetDeliveryProvider.parentFormModel.flagFunctionPerformance = _isPass(checklist, 'Functional Performance As Per Results Of Manufacturer Recommended Check List');
+ assetDeliveryProvider.parentFormModel.flagGroundingResistance = _isPass(checklist, 'Grounding Resistance: Ω');
+ assetDeliveryProvider.parentFormModel.flagChassiss = _isPass(checklist, 'Chassis Leakage Current: µA');
+ assetDeliveryProvider.parentFormModel.flagLeadsLeakage = _isPass(checklist, 'Leads Leakage Current: µA');
+ assetDeliveryProvider.parentFormModel.flagAlert = _isPass(checklist, 'This Device Is Not Subject To Any Alert Or Recall Until The Date Of Preparation Of This Inspection Form');
+ }
+
+ void applyInspectionFlagsToChecklist({
+ required TechnicalInspectionAssetModel model,
+ }) {
+ if (checkList.isEmpty) {
+ checkList = AssetDeliveryUtils.inspectionChecklist;
+ }
+ for (final item in checkList) {
+ switch (item.value) {
+ case 'flagphysicalInspection':
+ item.status = _statusFromBool(model.flagphysicalInspection);
+ break;
+
+ case 'flagFunctionPerformance':
+ item.status = _statusFromBool(model.flagFunctionPerformance);
+ break;
+
+ case 'flagGroundingResistance':
+ item.status = _statusFromBool(model.flagGroundingResistance);
+ break;
+
+ case 'flagChassiss':
+ item.status = _statusFromBool(model.flagChassiss);
+ break;
+
+ case 'flagLeadsLeakage':
+ item.status = _statusFromBool(model.flagLeadsLeakage);
+ break;
+
+ case 'flagAlert':
+ item.status = _statusFromBool(model.flagAlert);
+ break;
+ }
+ }
+ }
+
+ String _statusFromBool(bool? value) {
+ return value == true ? 'PASS' : 'FAIL';
+ }
+}
diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart
new file mode 100644
index 00000000..035fffe3
--- /dev/null
+++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_technical_inspection_lines_view.dart
@@ -0,0 +1,285 @@
+import 'dart:developer';
+
+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/lookup.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/delivery_line_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_form_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_cost_center_card_view.dart';
+import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_parent_asset_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/power_supply_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/single_item_drop_down_menu.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+import '../../../../new_views/common_widgets/app_filled_button.dart';
+import '../../../../new_views/common_widgets/default_app_bar.dart';
+
+class UpdateTechnicalInspectionLinesView extends StatefulWidget {
+ static const String id = "/technical-inspection-form";
+ final AssetDeliveryTableModel deliveryTableModel;
+ final AssetDeliveryDataModel? requestModel;
+ final DeliveryLineModel? deliveryLineModel;
+
+ UpdateTechnicalInspectionLinesView({
+ Key? key,
+ required this.deliveryTableModel,
+ this.requestModel,
+ this.deliveryLineModel,
+ }) : super(key: key);
+
+ @override
+ State createState() => _UpdateTechnicalInspectionLinesViewState();
+}
+
+class _UpdateTechnicalInspectionLinesViewState extends State {
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ TechnicalInspectionFormModel model = TechnicalInspectionFormModel();
+ AssetDeliveryProvider? assetDeliveryProvider;
+ bool isLoading = false;
+
+ @override
+ void initState() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ void getInitialData() async {
+ assetDeliveryProvider = Provider.of(context, listen: false);
+ isLoading = true;
+ setState(() {});
+ model = await assetDeliveryProvider!.getTechnicalInspectionData(
+ lineId: widget.deliveryLineModel?.id,
+ tableId: widget.deliveryTableModel.id,
+ );
+ isLoading = false;
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(
+ title: 'Technical Inspection'.addTranslation,
+ titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ body: Form(
+ key: _formKey,
+ child: isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ itemDetails(context: context, itemNo: widget.deliveryLineModel?.itemNumber, itemDescription: widget.deliveryLineModel?.itemDescription),
+ 12.height,
+ inspectionDetailsForm(),
+ 8.height,
+ const Divider().defaultStyle(context),
+ Text(
+ "Cost Centers",
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
+ ),
+ 8.height,
+ costCenterList(context),
+ ],
+ ).toShadowContainer(context, borderRadius: 20, padding: 12))
+ .expanded,
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget costCenterList(BuildContext context) {
+ List costCenterList = model.costCenters ?? [];
+ return costCenterList.isEmpty
+ ? const NoDataFound().center
+ : ListView.separated(
+ itemCount: costCenterList.length,
+ separatorBuilder: (_, __) => 8.height,
+ padding: EdgeInsets.zero,
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ itemBuilder: (listContext, itemIndex) {
+ return TechnicalInspectionCostCard(
+ costModel: costCenterList[itemIndex],
+ editPress: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => TechnicalInspectionParentAssetListView(
+ costCenterId: costCenterList[itemIndex].id,
+ tableItemId: widget.deliveryTableModel.id,
+ lineId: widget.deliveryLineModel?.id,
+ )));
+ },
+ isViewOnly: false,
+ );
+ },
+ );
+ }
+
+ Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ 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),
+ ),
+ 8.height,
+ Text(
+ itemDescription ?? '-',
+ style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
+ ),
+ ],
+ );
+ }
+
+ Widget inspectionDetailsForm() {
+ return Column(
+ children: [
+ SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Power Supply Type'.addTranslation,
+ titleTextColor: AppColor.neutral120,
+ showShadow: false,
+ validator: (value) {
+ if (value == null) return 'Please select power supply type';
+ return null;
+ },
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ initialValue: model.powerSupplyType,
+ onSelect: (value) {
+ if (value != null) {
+ model.powerSupplyType = value;
+ setState(() {});
+ }
+ },
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Power Reading'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.powerReading != null ? model.powerReading.toString() : '',
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onSaved: (value) {
+ model.powerReading = int.tryParse(value);
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Max Current'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.maxCurrent != null ? model.maxCurrent.toString() : '',
+ textAlign: TextAlign.center,
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ textInputType: TextInputType.number,
+ showShadow: false,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onSaved: (value) {
+ model.maxCurrent = int.tryParse(value);
+ },
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Voltage'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ textInputType: TextInputType.number,
+ initialValue: model.voltage != null ? model.voltage.toString() : '',
+ textAlign: TextAlign.center,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onSaved: (value) {
+ model.voltage = int.tryParse(value);
+ },
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ 8.height,
+ AppTextFormField(
+ labelText: 'Frequency'.addTranslation,
+ backgroundColor: AppColor.fieldBgColor(context),
+ initialValue: model.frequency != null ? model.frequency.toString() : '',
+ textInputType: TextInputType.number,
+ textAlign: TextAlign.center,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
+ onSaved: (value) {
+ model.frequency = int.tryParse(value);
+ },
+ labelStyle: AppTextStyles.textFieldLabelStyle,
+ showShadow: false,
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ ],
+ );
+ }
+
+ void _saveTap() async {
+ if (!_formKey.currentState!.validate()) return;
+ _formKey.currentState!.save();
+ model.tableItemId = widget.deliveryTableModel.id;
+ model.lineId = widget.deliveryLineModel?.id;
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await assetDeliveryProvider?.saveTechnicalInspection(model: model).then((status) async {
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ }
+ });
+ }
+}
diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart
new file mode 100644
index 00000000..6516b500
--- /dev/null
+++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart
@@ -0,0 +1,736 @@
+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/generic_attachment_model.dart';
+import 'package:test_sa/models/module_permissions_model.dart';
+import 'package:test_sa/models/new_models/building.dart';
+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';
+import 'package:test_sa/modules/asset_delivery_module/models/history_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
+import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_form_model.dart';
+import '../../../models/new_models/department.dart';
+import '../../../models/new_models/site.dart';
+import '../models/oracle_user_model.dart';
+
+class AssetDeliveryProvider extends ChangeNotifier {
+ final pageItemNumber = 10;
+ final searchPageItemNumber = 10;
+ int pageNo = 1;
+ AssetDeliveryDataModel? assetDeliveryDataModel;
+ List assetDeliveryTableList = [];
+ List deliveryLinesList = [];
+ ModulesPermissionsModel? modelPermission;
+ TechnicalInspectionAssetModel parentFormModel = TechnicalInspectionAssetModel();
+ TechnicalInspectionAssetModel childFormModel = TechnicalInspectionAssetModel();
+
+ void reset() {
+ pageNo = 1;
+ stateCode = null;
+ }
+
+ int? stateCode;
+ bool isDetailLoading = false;
+ bool nextPage = false;
+ bool isLoading = false;
+ bool isSiteLoading = false;
+ bool isDeliveryTableListLoading = false;
+ bool isDeliveryLineListLoading = false;
+ bool isChildAssetDataLoading = false;
+
+ void setParentModel(TechnicalInspectionAssetModel m) {
+ parentFormModel = m;
+ notifyListeners();
+ }
+
+ void setChildModel(TechnicalInspectionAssetModel m) {
+ childFormModel = m;
+ notifyListeners();
+ }
+
+ Future getAssetDeliveryDetailById({int? requestId}) async {
+ try {
+ assetDeliveryDataModel = AssetDeliveryDataModel();
+ isLoading = true;
+ notifyListeners();
+ final response = await ApiManager.instance.get(URLs.getAssetDeliveryDetailsById + "?Id=$requestId");
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ assetDeliveryDataModel = AssetDeliveryDataModel.fromJson(json.decode(response.body)["data"]);
+ } else {
+ assetDeliveryDataModel = null;
+ }
+ isLoading = false;
+ notifyListeners();
+ return assetDeliveryDataModel;
+ } catch (e) {
+ log("getdelivery details [error] : $e");
+ isLoading = false;
+ assetDeliveryDataModel = null;
+ notifyListeners();
+ return assetDeliveryDataModel;
+ }
+ }
+
+ Future getAssetDeliveryTableListById({int? requestId}) async {
+ try {
+ assetDeliveryTableList.clear();
+ isDeliveryTableListLoading = true;
+ notifyListeners();
+
+ final response = await ApiManager.instance.get(
+ "${URLs.getAssetDeliveryTableListById}?assetDeliveryExternalMasterId=$requestId",
+ );
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final jsonData = json.decode(response.body)["data"];
+ if (jsonData is List) {
+ assetDeliveryTableList = jsonData.map((e) => AssetDeliveryTableModel.fromJson(e)).toList();
+ } else {
+ assetDeliveryTableList = [];
+ }
+ } else {
+ assetDeliveryTableList = [];
+ }
+
+ isDeliveryTableListLoading = false;
+ notifyListeners();
+ } catch (e) {
+ log("get Delivery Table details [error] : $e");
+ isDeliveryTableListLoading = false;
+ assetDeliveryTableList = [];
+ notifyListeners();
+ }
+ }
+
+ Future getDeliveryLinesListById({int? itemId}) async {
+ try {
+ deliveryLinesList.clear();
+ isDeliveryLineListLoading = true;
+ notifyListeners();
+ final response = await ApiManager.instance.get(
+ "${URLs.getLineFromExternalPo}?assetDeliveryExternalDeliveryId=$itemId",
+ );
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final jsonData = json.decode(response.body)["data"];
+ if (jsonData is List) {
+ deliveryLinesList = jsonData.map((e) => DeliveryLineModel.fromJson(e)).toList();
+ } else {
+ deliveryLinesList = [];
+ }
+ } else {
+ deliveryLinesList = [];
+ }
+ isDeliveryLineListLoading = false;
+ notifyListeners();
+ } catch (e) {
+ log("get Delivery Lines List [error] : $e");
+ isDeliveryLineListLoading = false;
+ deliveryLinesList = [];
+ notifyListeners();
+ }
+ }
+
+ Future> getTechnicalInspectionLinesListById({int? itemId}) async {
+ List