diff --git a/assets/images/attachment_icon.svg b/assets/images/attachment_icon.svg
new file mode 100644
index 00000000..d0da9eaf
--- /dev/null
+++ b/assets/images/attachment_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/collesped_arrow_icon.svg b/assets/images/collesped_arrow_icon.svg
new file mode 100644
index 00000000..7980fef7
--- /dev/null
+++ b/assets/images/collesped_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/expended_arrow_icon.svg b/assets/images/expended_arrow_icon.svg
new file mode 100644
index 00000000..c1085125
--- /dev/null
+++ b/assets/images/expended_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart
index cfead080..2e7e5f56 100644
--- a/lib/controllers/api_routes/urls.dart
+++ b/lib/controllers/api_routes/urls.dart
@@ -270,7 +270,9 @@ class URLs {
//Traf
static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get
static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // get
+ static get getAssetAnalytics => "$_baseUrl/Asset/GetAssetAnalytics"; // get
static get getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get
+ static get getAssetNameAutoComplete => "$_baseUrl/AssetNameDefinition/GetAssetNameAutoComplete"; // get// get
//gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
@@ -307,11 +309,13 @@ class URLs {
static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get
static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get
static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get
+ static get getUserByRoleValueSiteMobileAutocomplete => "$_baseUrl/Account/GetUserByRoleValueSiteMobileAutocomplete"; // get
// pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get
static get updatePentry => "$_baseUrl/Visit/UpdateVisit"; // get
static get getPentryTaskStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=403"; // get
+ // get
static get getPentryVisitStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=402"; // get
static get getPentryStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=401"; // get
// contacts
@@ -347,11 +351,22 @@ class URLs {
static get getClassification => '$_baseUrl/AssetInventory/Classification';
+ //internal Audit
+ static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById";
+ static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2";
+ static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43";
+ static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500";
+ static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502";
+ static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment";
+ static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem";
+ static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder";
+ static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer";
+ static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer";
+ static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
+
//chat
static get chatSdkToken => '$chatHubUrlApi/auth/sdk-token';
-
//survey
static get getQuestionnaire => '$_baseUrl/SurveyQuestionnaire/GetQuestionnaire';
-
static get submitSurvey => '$_baseUrl/SurveyQuestionnaire/SubmitSurvey';
}
diff --git a/lib/controllers/providers/api/all_requests_provider.dart b/lib/controllers/providers/api/all_requests_provider.dart
index 470f803d..99f77a02 100644
--- a/lib/controllers/providers/api/all_requests_provider.dart
+++ b/lib/controllers/providers/api/all_requests_provider.dart
@@ -133,15 +133,24 @@ class AllRequestsProvider extends ChangeNotifier {
List getStatues(BuildContext context) {
List list = [1, 2, 3, 4];
+ //TODO need to refactor this code ....
if (context.userProvider.isAssessor) {
list = [9];
return list;
}
+ if (context.userProvider.isQualityUser) {
+
+ list = [10,11];
+ return list;
+ }
if (!context.userProvider.isNurse) {
list.add(5);
}
+ if (context.userProvider.isEngineer) {
+ list.add(10);
+ }
list.add(6); // task module
if (context.settingProvider.isUserFlowMedical && !context.userProvider.isNurse) {
diff --git a/lib/controllers/providers/api/oracle_code_provider.dart b/lib/controllers/providers/api/oracle_code_provider.dart
index ea8b0978..71375675 100644
--- a/lib/controllers/providers/api/oracle_code_provider.dart
+++ b/lib/controllers/providers/api/oracle_code_provider.dart
@@ -88,7 +88,7 @@ class OracleCodeProvider extends ChangeNotifier {
Future> getAssetByOracleCode(String oracleCode) async {
late Response response;
try {
- response = await ApiManager.instance.post(URLs.getAssetNDAutoCompleteByDynamicCodes, body: {"codeValue": oracleCode});
+ response = await ApiManager.instance.post(URLs.getAssetNameAutoComplete, body: {"pageSize": 1, "pageNumber": 20, "searchText": oracleCode});
List page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
diff --git a/lib/controllers/providers/api/search_user_provider.dart b/lib/controllers/providers/api/search_user_provider.dart
index cdaecdb2..f13a30ca 100644
--- a/lib/controllers/providers/api/search_user_provider.dart
+++ b/lib/controllers/providers/api/search_user_provider.dart
@@ -46,10 +46,10 @@ class UserSearchProvider extends ChangeNotifier {
notifyListeners();
}
- Future> getUsersBasedOnSearch(String query) async {
+ Future> getUsersBasedOnSearch(int siteId, String query) async {
late Response response;
try {
- response = await ApiManager.instance.get(URLs.getUsersBasedOnSearch + "?roleValue=R-7&searchText=$query");
+ response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=$siteId&roleValue=R-7&searchText=$query");
List page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart
index 481d06d5..471be087 100644
--- a/lib/controllers/providers/api/user_provider.dart
+++ b/lib/controllers/providers/api/user_provider.dart
@@ -45,6 +45,7 @@ class UserProvider extends ChangeNotifier {
bool get isNurse => user!.type == UsersTypes.normal_user;
bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl;
+ bool get isQualityUser => user!.type == UsersTypes.qualityUser;
VerifyOtpModel _verifyOtpModel = VerifyOtpModel();
SwipeTransaction _swipeTransactionModel = SwipeTransaction();
diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart
index 07d5d92d..9ca9daff 100644
--- a/lib/dashboard_latest/widgets/request_category_list.dart
+++ b/lib/dashboard_latest/widgets/request_category_list.dart
@@ -3,6 +3,7 @@ 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_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_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@@ -56,6 +57,11 @@ class RequestCategoryList extends StatelessWidget {
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
+ //TODO need to verify this ...
+ case 10:
+ return EquipmentInternalAuditItemView(requestData: request);
+ case 11:
+ return EquipmentInternalAuditItemView(requestData: request);
default:
return Container(
height: 100,
diff --git a/lib/main.dart b/lib/main.dart
index 6b47386e..8855155a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -31,6 +31,12 @@ import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.dart';
@@ -100,6 +106,8 @@ import 'controllers/providers/api/gas_refill_comments.dart';
import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'dashboard_latest/dashboard_provider.dart';
+import 'modules/internal_audit_module/pages/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 'new_views/pages/gas_refill_request_form.dart';
import 'providers/lookups/classification_lookup_provider.dart';
@@ -291,6 +299,10 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PpmServiceProvider()),
ChangeNotifierProvider(create: (_) => CommentsProvider()),
ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()),
+ ChangeNotifierProvider(create: (_) => InternalAuditCheckListProvider()),
+ ChangeNotifierProvider(create: (_) => InternalAuditWoTypeProvider()),
+ ChangeNotifierProvider(create: (_) => InternalAuditProvider()),
+ ChangeNotifierProvider(create: (_) => InternalAuditFindingTypeProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => RequestStatusProvider()),
@@ -359,6 +371,10 @@ class MyApp extends StatelessWidget {
ProfilePage.id: (_) => const ProfilePage(),
ReportBugPage.id: (_) => const ReportBugPage(),
HelpCenterPage.id: (_) => const HelpCenterPage(),
+ CreateEquipmentInternalAuditForm.id: (_) => const CreateEquipmentInternalAuditForm(),
+ CreateSystemInternalAuditForm.id: (_) => const CreateSystemInternalAuditForm(),
+ UpdateEquipmentInternalAuditPage.id: (_) => UpdateEquipmentInternalAuditPage(),
+ UpdateSystemInternalAuditPage.id: (_) => UpdateSystemInternalAuditPage(),
// SwipeSuccessView.routeName: (_) => const SwipeSuccessView(),
// SwipeHistoryView.routeName: (_) => const SwipeHistoryView(),
},
diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart
index 63f1d9d7..cd6b5f13 100644
--- a/lib/models/enums/user_types.dart
+++ b/lib/models/enums/user_types.dart
@@ -3,5 +3,6 @@ enum UsersTypes {
normal_user, // 1
nurse, // 1
assessor,
- assessorTl
+ assessorTl,
+ qualityUser
}
diff --git a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart
index dda5432b..21541769 100644
--- a/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart
+++ b/lib/models/helper_data_models/maintenance_request/activity_maintenance_model.dart
@@ -31,11 +31,11 @@ class ActivityMaintenanceHelperModel {
WorkOrderAssignedEmployee? assignedEmployee;
SuppEngineerWorkOrders? supEngineer;
ActivityMaintenanceAssistantEmployees? modelAssistantEmployees;
+ List? assistantEmployList=[];
List? assistantEmployees;
List? activityMaintenanceTimers = [];
TimerModel? activityMaintenanceTimerModel = TimerModel();
TimerModel? activityTimePicker;
- List? assistantEmployList=[];
List? timerModelList = [];
ActivityMaintenanceHelperModel(
diff --git a/lib/models/new_models/users_based_on_search_model.dart b/lib/models/new_models/users_based_on_search_model.dart
index 54480f91..4dea3117 100644
--- a/lib/models/new_models/users_based_on_search_model.dart
+++ b/lib/models/new_models/users_based_on_search_model.dart
@@ -6,17 +6,11 @@ class UsersBasedOnSearchModel {
int? languageId;
String? extensionNo;
String? phoneNumber;
+ String? positionName;
+ String? position;
bool? isActive;
- UsersBasedOnSearchModel(
- {this.userId,
- this.userName,
- this.email,
- this.employeeId,
- this.languageId,
- this.extensionNo,
- this.phoneNumber,
- this.isActive});
+ UsersBasedOnSearchModel({this.userId, this.userName, this.email, this.employeeId, this.languageId, this.extensionNo, this.phoneNumber, this.positionName, this.position, this.isActive});
UsersBasedOnSearchModel.fromJson(Map json) {
userId = json['userId'];
@@ -26,6 +20,8 @@ class UsersBasedOnSearchModel {
languageId = json['languageId'];
extensionNo = json['extensionNo'];
phoneNumber = json['phoneNumber'];
+ positionName = json['positionName'];
+ position = json['position'];
isActive = json['isActive'];
}
@@ -38,6 +34,8 @@ class UsersBasedOnSearchModel {
data['languageId'] = this.languageId;
data['extensionNo'] = this.extensionNo;
data['phoneNumber'] = this.phoneNumber;
+ data['positionName'] = this.positionName;
+ data['position'] = this.position;
data['isActive'] = this.isActive;
return data;
}
diff --git a/lib/models/user.dart b/lib/models/user.dart
index 20158748..2fd42598 100644
--- a/lib/models/user.dart
+++ b/lib/models/user.dart
@@ -1,3 +1,4 @@
+import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
@@ -107,6 +108,8 @@ class User {
return UsersTypes.assessor;
case "R-19": // Head Nurse Role
return UsersTypes.assessorTl;
+ case "R-3": // Quality User
+ return UsersTypes.qualityUser;
default:
return null;
}
diff --git a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart
index 0b6796cb..4a4e6587 100644
--- a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart
+++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart
@@ -100,13 +100,13 @@ class AssetInventoryModel {
String? photo;
String? photoOriginName;
String? remarks;
-
Site? site;
Building? building;
Floor? floor;
Department? department;
Rooms? room;
SupplierDetails? supplier;
+ List assetInventoryDetailAssetAttachments = [];
AssetInventoryModel({
this.id,
@@ -160,6 +160,7 @@ class AssetInventoryModel {
this.floor,
this.room,
this.supplier,
+ this.assetInventoryDetailAssetAttachments = const [],
});
AssetInventoryModel.fromJson(Map json) {
@@ -194,6 +195,13 @@ class AssetInventoryModel {
photo = json['photo'];
photoOriginName = json['photoOriginName'];
remarks = json['remarks'];
+ if (json['assetTransferAttachments'] != null) {
+ assetInventoryDetailAssetAttachments = [];
+ json['assetInventoryDetailAssetAttachments'].forEach((v) {
+ assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v));
+ });
+ }
+
//new data..
// newAssetNumber = json['newAssetNumber'] ?? json['assetNumber'];
// manufacturerId = json['manufacturerId'] ?? json['manufacturerId'];
@@ -232,6 +240,9 @@ class AssetInventoryModel {
'newSupplierName': newSupplierName,
'photo': photo,
'remarks': remarks,
+ 'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null
+ ? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList()
+ : [],
};
}
@@ -290,8 +301,45 @@ class AssetInventoryModel {
department: department ?? other.department,
room: room ?? other.room,
supplier: supplier ?? other.supplier,
+ assetInventoryDetailAssetAttachments: assetInventoryDetailAssetAttachments??other.assetInventoryDetailAssetAttachments,
);
}
}
+class AssetInventoryDetailAssetAttachments {
+ AssetInventoryDetailAssetAttachments({
+ this.id,
+ this.name,
+ this.originalName,
+ });
+
+ AssetInventoryDetailAssetAttachments.fromJson(dynamic json) {
+ id = json['id'];
+ name = json['name'];
+ originalName = json['originalName'];
+ }
+
+ num? id;
+ String? name;
+ String? originalName;
+
+ AssetInventoryDetailAssetAttachments copyWith({
+ num? id, // Parameter is now nullable
+ String? name, // Parameter is now nullable
+ String? originalName, // Parameter is now nullable
+ }) =>
+ AssetInventoryDetailAssetAttachments(
+ id: id ?? this.id,
+ name: name??this.name,
+ originalName: originalName??this.originalName,
+ );
+
+ Map toJson() {
+ final map = {};
+ map['id'] = id;
+ map['name'] = name;
+ map['originalName'] = originalName;
+ return map;
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart
index c49a836f..9d128718 100644
--- a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart
+++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart
@@ -24,6 +24,7 @@ class AssetDetailCardView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
@@ -37,81 +38,75 @@ class AssetDetailCardView extends StatelessWidget {
],
),
8.height,
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- 'transaction Date: ${assetInventoryModel.transactionDate?.toServiceRequestDetailsFormat ?? '-'}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.model}: ${assetInventoryModel.model ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${'Classifications'.addTranslation}: ${assetInventoryModel.status ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- Text(
- '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}',
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
- ),
- ],
- ).expanded,
- Container(
- decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)),
- height: 115.toScreenHeight,
- width: 115.toScreenWidth,
- margin: const EdgeInsets.only(top: 8),
- child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty
- ? ClipRRect(
- borderRadius: BorderRadius.circular(8),
- child: ImageLoader(
- url: URLs.getFileUrl(assetInventoryModel.photo),
- boxFit: BoxFit.cover,
- height: 48,
- width: 48,
- ))
- : 'image_placeholder'.toSvgAsset().center,
- )
- ],
+ Text(
+ 'Inventory Date: ${assetInventoryModel.transactionDate?.toServiceRequestDetailsFormat ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ), Text(
+ '${context.translation.assetName}: ${assetInventoryModel.assetName ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.manufacture}: ${assetInventoryModel.manufacturer ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.model}: ${assetInventoryModel.model ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${context.translation.supplier}: ${assetInventoryModel.supplierName ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${'Classifications'.addTranslation}: ${assetInventoryModel.status ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
+ ),
+ Text(
+ '${'Remarks'.addTranslation}: ${assetInventoryModel.remarks ?? ''}',
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
}
+//TODO old code.
+// Container(
+// decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)),
+// height: 115.toScreenHeight,
+// width: 115.toScreenWidth,
+// margin: const EdgeInsets.only(top: 8),
+// child: assetInventoryModel.photo != null && assetInventoryModel.photo!.isNotEmpty
+// ? ClipRRect(
+// borderRadius: BorderRadius.circular(8),
+// child: ImageLoader(
+// url: URLs.getFileUrl(assetInventoryModel.photo),
+// boxFit: BoxFit.cover,
+// height: 48,
+// width: 48,
+// ))
+// : 'image_placeholder'.toSvgAsset().center,
+// )
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart
index 5c826f56..9337013a 100644
--- a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart
@@ -4,6 +4,7 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@@ -48,12 +49,15 @@ class _AssetInventoryDetailViewState extends State {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
+ //
StatusLabel(
label: sessionModel.statusName,
id: sessionModel.statusId,
radius: 4,
- textColor: AppColor.green15,
- backgroundColor: AppColor.greenStatus(context),
+ textColor: AppColor.getRequestStatusTextColorByName(context, sessionModel.statusName),
+ backgroundColor: AppColor.getRequestStatusColorByName(context, sessionModel.statusName),
+ // textColor: AppColor.green15,
+ // backgroundColor: AppColor.greenStatus(context),
),
Text(
sessionModel.createdDate!.toString().toServiceRequestCardFormat,
@@ -64,7 +68,7 @@ class _AssetInventoryDetailViewState extends State {
),
8.height,
Text(
- context.translation.requestDetails,
+ 'Session Details'.addTranslation,
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
@@ -100,64 +104,139 @@ class _AssetInventoryDetailViewState extends State {
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
- ListView.separated(
- physics: const NeverScrollableScrollPhysics(),
- shrinkWrap: true,
- padding: EdgeInsets.zero,
- itemCount: sites.length,
- itemBuilder: (cxt, siteIndex) {
- final site = sites[siteIndex];
- final buildingNames = (site.buildings ?? []).map((b) => b.name).where((name) => name != null && name!.trim().isNotEmpty).join(', ');
- final floorNames = (site.buildings ?? []).expand((b) => b.floors ?? []).map((f) => f.name).where((name) => name != null && name!.trim().isNotEmpty).join(', ');
- final departmentNames =
- (site.buildings ?? []).expand((b) => b.floors ?? []).expand((f) => f.departments ?? []).map((d) => d.name).where((name) => name != null && name!.trim().isNotEmpty).join(', ');
- final roomNames = (site.buildings ?? [])
- .expand((b) => b.floors ?? [])
- .expand((f) => f.departments ?? [])
- .expand((d) => d.rooms ?? [])
- .map((r) => r.name)
- .where((name) => name != null && name!.trim().isNotEmpty)
- .join(', ');
-
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ SiteHierarchyView(
+ sites: sites,
+ ),
+ ],
+ ).toShadowContainer(context, padding: 12, borderRadius: 20);
+ }
+}
+
+
+
+class SiteHierarchyView extends StatelessWidget {
+ final List sites;
+
+ const SiteHierarchyView({super.key, required this.sites});
+
+ @override
+ Widget build(BuildContext context) {
+ return ListView.builder(
+ physics: const NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemCount: sites.length,
+ itemBuilder: (context, index) {
+ final site = sites[index];
+ return HierarchyTile(
+ title: site.name ?? '-',
+ children: (site.buildings ?? [])
+ .map((b) => HierarchyTile(
+ title: b.name ?? '-',
+ children: (b.floors ?? [])
+ .map((f) => HierarchyTile(
+ title: f.name ?? '-',
+ children: (f.departments ?? [])
+ .map((d) => HierarchyTile(
+ title: d.name ?? '-',
+ children: (d.rooms ?? [])
+ .map((r) => LeafTile(title: r.name ?? '-'))
+ .toList(),
+ ))
+ .toList(),
+ ))
+ .toList(),
+ ))
+ .toList(),
+ );
+ },
+ );
+ }
+}
+class HierarchyTile extends StatefulWidget {
+ final String title;
+ final List children;
+ final double indent;
+
+ const HierarchyTile({
+ super.key,
+ required this.title,
+ this.children = const [],
+ this.indent = 0,
+ });
+
+ @override
+ State createState() => _HierarchyTileState();
+}
+
+class _HierarchyTileState extends State {
+ bool expanded = false;
+
+ @override
+ Widget build(BuildContext context) {
+ final hasChildren = widget.children.isNotEmpty;
+ return Padding(
+ padding: EdgeInsets.only(left: widget.indent,top: 10.toScreenHeight),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: hasChildren ? () => setState(() => expanded = !expanded) : null,
+ child: Row(
children: [
+ if (hasChildren)
+ // expanded? 'expended_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13): 'collesped_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13)
+ Icon(
+ expanded ? Icons.expand_more : Icons.chevron_right,
+ size: 25.toScreenHeight,
+ color: AppColor.neutral50,
+ )
+ else
+ SizedBox(width: 18.toScreenWidth),
+ SizedBox(width: 15.toScreenWidth),
Text(
- site.name ?? '-',
- style: AppTextStyles.heading6.copyWith(
- color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
- ),
- ),
- Text(
- '${context.translation.building}: ${buildingNames.isNotEmpty ? buildingNames : '-'}',
- style: AppTextStyles.bodyText.copyWith(
- color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
- ),
- ),
- Text(
- '${context.translation.floor}: ${floorNames.isNotEmpty ? floorNames : '-'}',
- style: AppTextStyles.bodyText.copyWith(
- color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
- ),
- ),
- Text(
- '${context.translation.department}: ${departmentNames.isNotEmpty ? departmentNames : '-'}',
- style: AppTextStyles.bodyText.copyWith(
- color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
- ),
- ),
- Text(
- '${context.translation.room}: ${roomNames.isNotEmpty ? roomNames : '-'}',
- style: AppTextStyles.bodyText.copyWith(
- color: context.isDark ? AppColor.neutral10 : AppColor.neutral120,
- ),
+ widget.title,
+ style:AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
- );
- },
- separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),
- ),
- ],
- ).toShadowContainer(context, padding: 12, borderRadius: 20);
+ ),
+ ),
+ if (expanded)
+ Padding(
+ padding: const EdgeInsets.only(left: 20, top: 6),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: widget.children
+ .map((child) => child is HierarchyTile
+ ? HierarchyTile(
+ title: (child).title,
+ indent: 0,
+ children: (child).children,
+ )
+ : child)
+ .toList(),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+class LeafTile extends StatelessWidget {
+ final String title;
+
+ const LeafTile({super.key, required this.title});
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(left: 22, top: 4, bottom: 4),
+ child: Text(
+ title,
+ style: const TextStyle(fontSize: 13, color: Colors.black87),
+ ),
+ );
}
}
+
+
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart
index fd4bea7c..f6c2e0b2 100644
--- a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart
@@ -294,30 +294,17 @@ class _AssetInventoryFormViewState extends State {
],
12.height,
Text(
- 'Asset Photo'.addTranslation,
+ 'Attachments'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936),
),
12.height,
- attachments.isEmpty
- ? AttachmentPicker(
- label: context.translation.attachImage,
- attachment: attachments,
- buttonColor: AppColor.black10,
- onlyImages: true,
- onChange: (value) {
- setState(() {});
- },
- buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
- )
- : MultiFilesPickerItem(
- file: File(attachments.first.name ?? ''),
- enabled: true,
- onRemoveTap: (file) {
- setState(() {
- attachments.clear();
- });
- },
- ),
+ AttachmentPicker(
+ label: context.translation.attachFiles,
+ attachment: attachments,
+ buttonColor: AppColor.black10,
+ onlyImages: false,
+ buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
+ ),
12.height,
AppTextFormField(
backgroundColor: AppColor.fieldBgColor(context),
@@ -338,7 +325,7 @@ class _AssetInventoryFormViewState extends State {
.expanded,
FooterActionButton.footerContainer(
context: context,
- child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit),
+ child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Submit'.addTranslation, maxWidth: true, onPressed: _onSubmit),
),
],
),
@@ -348,7 +335,6 @@ class _AssetInventoryFormViewState extends State {
Future searchAsset({required String assetNo}) async {
AssetInventoryProvider provider = Provider.of(context, listen: false);
-
Map payload = {
"assetNumber": assetNo,
"sessionId": widget.assetInventoryModel?.sessionId,
@@ -415,11 +401,20 @@ class _AssetInventoryFormViewState extends State {
_scannedAssetModel?.departmentId = widget.assetInventoryModel?.department?.id;
_scannedAssetModel?.roomId = widget.assetInventoryModel?.room?.id;
_scannedAssetModel?.isNotRegistered = isRegistered;
- if (attachments.isNotEmpty) {
- String? photoName = attachments.first.name;
- String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? '';
- _scannedAssetModel?.photo = fileName;
+ _scannedAssetModel?.assetInventoryDetailAssetAttachments = [];
+ // try {
+ for (var item in attachments) {
+ String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
+ _scannedAssetModel?.assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments(id: item.id, name: fileName));
}
+ // // } catch (error) {
+ // // print(error);
+ // // }
+ // if (attachments.isNotEmpty) {
+ // String? photoName = attachments.first.name;
+ // String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? '';
+ // _scannedAssetModel?.photo = fileName;
+ // }
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) async {
///Need to use push and remove until...
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart
index 88e21b07..6240373c 100644
--- a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart
@@ -58,7 +58,7 @@ class _AssetInventoryPageState extends State {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar(
- title: 'Inventory Session Request'.addTranslation,
+ title: 'Asset Inventory Session'.addTranslation,
onBackPress: () {
Navigator.pop(context);
},
@@ -86,7 +86,7 @@ class _AssetInventoryPageState extends State {
indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)),
onTap: (index) {},
tabs: [
- Tab(text: 'Request Details'.addTranslation, height: 57.toScreenHeight),
+ Tab(text: 'Session Details'.addTranslation, height: 57.toScreenHeight),
Tab(
text:
'${'Scan Assets'.addTranslation} ${provider.assetInventoryResponse?.totalRows != null && provider.assetInventoryResponse!.totalRows! > 0 ? '(${provider.assetInventoryResponse?.totalRows})' : ''}',
diff --git a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart
index 8d9abfdd..12adb610 100644
--- a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart
+++ b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart
@@ -26,12 +26,6 @@ class InventorySessionItemView extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- StatusLabel(
- label: requestData!.priorityName!,
- textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!),
- backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!),
- ),
- 8.width,
StatusLabel(
label: requestData!.statusName!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
@@ -47,7 +41,7 @@ class InventorySessionItemView extends StatelessWidget {
),
8.height,
(requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context),
- infoWidget(label: context.translation.requestType, value: requestData?.sessionType, context: context),
+ infoWidget(label: 'Session Type'.addTranslation, value: requestData?.sessionType, context: context),
infoWidget(label: 'No of Assets'.addTranslation, value: requestData?.numberOfAssets != null ? requestData?.numberOfAssets.toString() : '-', context: context),
infoWidget(label: 'No of Sites'.addTranslation, value: requestData?.numberOfSites != null ? requestData?.numberOfSites.toString() : '-', context: context),
8.height,
@@ -73,12 +67,6 @@ class InventorySessionItemView extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- StatusLabel(
- label: requestDetails!.priority!,
- textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!),
- backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!),
- ),
- 8.width,
StatusLabel(
label: requestDetails!.status!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
@@ -94,7 +82,7 @@ class InventorySessionItemView extends StatelessWidget {
),
8.height,
(requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context),
- infoWidget(label: context.translation.requestType, value: requestDetails?.sessionType, context: context),
+ infoWidget(label: 'Session Type'.addTranslation, value: requestDetails?.sessionType, context: context),
infoWidget(label: 'No of Assets'.addTranslation, value: requestDetails?.numberOfAssets != null ? requestDetails?.numberOfAssets.toString() : '-', context: context),
infoWidget(label: 'No of Sites'.addTranslation, value: requestDetails?.numberOfSites != null ? requestDetails?.numberOfSites.toString() : '-', context: context),
8.height,
diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart
index 992c0060..440715e9 100644
--- a/lib/modules/cm_module/views/components/service_request_detail_view.dart
+++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart
@@ -72,52 +72,44 @@ class _ServiceRequestDetailViewState extends State {
? const CircularProgressIndicator(color: AppColor.primary10).center
: requestProvider.currentWorkOrder == null
? const NoDataFound()
- : Stack(
- children: [
- Column(
+ : Column(
+ children: [
+ SingleChildScrollView(
+ padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- SingleChildScrollView(
- padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider),
- initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
- 12.height,
- assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
- 12.height,
- if (context.userProvider.user!.type == UsersTypes.engineer &&
- !requestProvider.isReadOnlyRequest &&
- requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[
- costCard(context, requestProvider),
- 12.height,
- ],
- contactInfoCard(context, requestProvider.currentWorkOrder!.data!),
- 20.height,
- ],
- ),
- ).expanded,
- SafeArea(
- top: false,
- right: false,
- left: false,
- child: FooterActionButton.requestDetailsFooterWidget(
- workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!,
- status: requestProvider.currentWorkOrder?.data?.status,
- isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null,
- activities: requestProvider.currentWorkOrder!.data?.activities ?? [],
- userProvider: _userProvider,
- context: context),
- ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
+ workOrderDetailCard(context, requestProvider.currentWorkOrder!.data!, _userProvider, requestProvider),
+ initialVisitCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
+ 12.height,
+ assetDetailCard(requestDetailProvider: requestProvider, userProvider: _userProvider),
+ 12.height,
+ if (context.userProvider.user!.type == UsersTypes.engineer &&
+ !requestProvider.isReadOnlyRequest &&
+ requestProvider.currentWorkOrder!.data!.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.activity) ...[
+ costCard(context, requestProvider),
+ 12.height,
+ ],
+ contactInfoCard(context, requestProvider.currentWorkOrder!.data!),
+ 20.height,
],
),
- //no need to show timer as discussed with backend
- // if (requestProvider.timer != null && requestProvider.timer!.isActive) ...[
- // const TimerWidget(),
- // ]
- ],
- );
+ ).expanded,
+ SafeArea(
+ top: false,
+ right: false,
+ left: false,
+ child: FooterActionButton.requestDetailsFooterWidget(
+ workOrderNextStepStatus: requestProvider.currentWorkOrder!.data!.nextStep!.workOrderNextStepEnum!,
+ status: requestProvider.currentWorkOrder?.data?.status,
+ isEmpIsAssigned: requestProvider.currentWorkOrder!.data!.assignedEmployee != null,
+ activities: requestProvider.currentWorkOrder!.data?.activities ?? [],
+ userProvider: _userProvider,
+ context: context),
+ ).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
+ ],
+ );
});
}
diff --git a/lib/modules/internal_audit_module/models/engineer_data_model.dart b/lib/modules/internal_audit_module/models/engineer_data_model.dart
new file mode 100644
index 00000000..dbb34d24
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/engineer_data_model.dart
@@ -0,0 +1,53 @@
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+
+class EngineerData {
+ int? id;
+ String? debrief;
+ String? startTime;
+ String? endTime;
+ double? totalHours;
+ bool? isComplete;
+ int? statusId;
+ int? requestId;
+ List? attachments;
+
+ EngineerData({
+ this.id,
+ this.debrief,
+ this.startTime,
+ this.endTime,
+ this.totalHours,
+ this.isComplete,
+ this.statusId,
+ this.requestId,
+ this.attachments,
+ });
+
+ EngineerData.fromJson(Map json) {
+ id = json['id'];
+ debrief = json['debrief'];
+ startTime = json['startTime'];
+ endTime = json['endTime'];
+ totalHours = (json['totalHours'] as num?)?.toDouble();
+ isComplete = json['isComplete'];
+ statusId = json['statusId'];
+ requestId = json['requestId'];
+ attachments = json['attachments'] != null ? (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList() : [];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['debrief'] = debrief;
+ data['startTime'] = startTime;
+ data['endTime'] = endTime;
+ data['totalHours'] = totalHours;
+ data['isComplete'] = isComplete;
+ data['statusId'] = statusId;
+ data['requestId'] = requestId;
+ if (attachments != null) {
+ data['attachments'] = attachments!.map((e) => e.toJson()).toList();
+ }
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart
new file mode 100644
index 00000000..92f41bab
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart
@@ -0,0 +1,300 @@
+ import 'package:test_sa/models/timer_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart';
+
+class EquipmentInternalAuditDataModel {
+ int? id;
+ String? requestNo;
+ String? createdDate;
+ int? requestNoSequence;
+ Auditor? auditor;
+ Status? status;
+ Asset? asset;
+ AssignEmployee? assignEmployee;
+ dynamic manufacture;
+ String? remarks;
+ List? equipmentsFindings;
+ List? attachments;
+ EngineerData? engineerData;
+
+
+ EquipmentInternalAuditDataModel({
+ this.id,
+ this.requestNo,
+ this.createdDate,
+ this.requestNoSequence,
+ this.auditor,
+ this.status,
+ this.asset,
+ this.assignEmployee,
+ this.manufacture,
+ this.remarks,
+ this.equipmentsFindings,
+ this.attachments,
+ this.engineerData,
+ });
+
+ EquipmentInternalAuditDataModel.fromJson(Map json) {
+ id = json['id'];
+ requestNo = json['requestNo'];
+ createdDate = json['createdDate'];
+ requestNoSequence = json['requestNoSequence'];
+ auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null;
+ status = json['status'] != null ? Status.fromJson(json['status']) : null;
+ asset = json['asset'] != null ? Asset.fromJson(json['asset']) : null;
+ assignEmployee = json['assignEmployee'] != null ? AssignEmployee.fromJson(json['assignEmployee']) : null;
+ manufacture = json['manufacture'];
+ remarks = json['remarks'];
+ if (json['equipmentsFindings'] != null) {
+ equipmentsFindings = [];
+ json['equipmentsFindings'].forEach((v) {
+ equipmentsFindings!.add(EquipmentsFinding.fromJson(v));
+ });
+ }
+ attachments = json['attachments'] != null
+ ? (json['attachments'] as List)
+ .map((e) => InternalAuditAttachments.fromJson(e))
+ .where((e) => e.name != null) // optional filter if you want to skip null names
+ .toList()
+ : [];
+ engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null;
+
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['requestNo'] = requestNo;
+ data['createdDate'] = createdDate;
+ data['requestNoSequence'] = requestNoSequence;
+ if (auditor != null) {
+ data['auditor'] = auditor!.toJson();
+ }
+ if (status != null) {
+ data['status'] = status!.toJson();
+ }
+ if (asset != null) {
+ data['asset'] = asset!.toJson();
+ }
+ if (assignEmployee != null) {
+ data['assignEmployee'] = assignEmployee!.toJson();
+ }
+ data['manufacture'] = manufacture;
+ data['remarks'] = remarks;
+ if (equipmentsFindings != null) {
+ data['equipmentsFindings'] =
+ equipmentsFindings!.map((v) => v.toJson()).toList();
+ }
+ data['attachments'] = attachments;
+ if (engineerData != null) data['engineerData'] = engineerData!.toJson();
+ return data;
+ }
+}
+
+class Auditor {
+ String? userId;
+ String? userName;
+ String? email;
+ String? employeeId;
+ int? languageId;
+ String? extensionNo;
+ String? phoneNumber;
+ bool? isActive;
+
+ Auditor({
+ this.userId,
+ this.userName,
+ this.email,
+ this.employeeId,
+ this.languageId,
+ this.extensionNo,
+ this.phoneNumber,
+ this.isActive,
+ });
+
+ Auditor.fromJson(Map json) {
+ userId = json['userId'];
+ userName = json['userName'];
+ email = json['email'];
+ employeeId = json['employeeId'];
+ languageId = json['languageId'];
+ extensionNo = json['extensionNo'];
+ phoneNumber = json['phoneNumber'];
+ isActive = json['isActive'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['userId'] = userId;
+ data['userName'] = userName;
+ data['email'] = email;
+ data['employeeId'] = employeeId;
+ data['languageId'] = languageId;
+ data['extensionNo'] = extensionNo;
+ data['phoneNumber'] = phoneNumber;
+ data['isActive'] = isActive;
+ return data;
+ }
+}
+
+class Status {
+ int? id;
+ String? name;
+ int? value;
+
+ Status({this.id, this.name, this.value});
+
+ Status.fromJson(Map json) {
+ id = json['id'];
+ name = json['name'];
+ value = json['value'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['name'] = name;
+ data['value'] = value;
+ return data;
+ }
+}
+
+class Asset {
+ int? id;
+ String? assetNumber;
+ String? assetSerialNo;
+ String? assetName;
+ String? modelName;
+ String? manufacturerName;
+ String? siteName;
+ int? siteId;
+ String? modelDefinition;
+
+ Asset({
+ this.id,
+ this.assetNumber,
+ this.assetSerialNo,
+ this.assetName,
+ this.modelName,
+ this.manufacturerName,
+ this.siteName,
+ this.siteId,
+ this.modelDefinition,
+ });
+
+ Asset.fromJson(Map json) {
+ id = json['id'];
+ assetNumber = json['assetNumber'];
+ assetSerialNo = json['assetSerialNo'];
+ assetName = json['assetName'];
+ modelName = json['modelName'];
+ manufacturerName = json['manufacturerName'];
+ siteName = json['siteName'];
+ siteId = json['siteId'];
+ modelDefinition = json['modelDefinition'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['assetNumber'] = assetNumber;
+ data['assetSerialNo'] = assetSerialNo;
+ data['assetName'] = assetName;
+ data['modelName'] = modelName;
+ data['manufacturerName'] = manufacturerName;
+ data['siteName'] = siteName;
+ data['siteId'] = siteId;
+ data['modelDefinition'] = modelDefinition;
+ return data;
+ }
+}
+
+class AssignEmployee {
+ String? userId;
+ String? userName;
+ String? email;
+ String? employeeId;
+ int? languageId;
+ String? extensionNo;
+ String? phoneNumber;
+ bool? isActive;
+
+ AssignEmployee({
+ this.userId,
+ this.userName,
+ this.email,
+ this.employeeId,
+ this.languageId,
+ this.extensionNo,
+ this.phoneNumber,
+ this.isActive,
+ });
+
+ AssignEmployee.fromJson(Map json) {
+ userId = json['userId'];
+ userName = json['userName'];
+ email = json['email'];
+ employeeId = json['employeeId'];
+ languageId = json['languageId'];
+ extensionNo = json['extensionNo'];
+ phoneNumber = json['phoneNumber'];
+ isActive = json['isActive'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['userId'] = userId;
+ data['userName'] = userName;
+ data['email'] = email;
+ data['employeeId'] = employeeId;
+ data['languageId'] = languageId;
+ data['extensionNo'] = extensionNo;
+ data['phoneNumber'] = phoneNumber;
+ data['isActive'] = isActive;
+ return data;
+ }
+}
+
+class EquipmentsFinding {
+ int? id;
+ Finding? finding;
+
+ EquipmentsFinding({this.id, this.finding});
+
+ EquipmentsFinding.fromJson(Map json) {
+ id = json['id'];
+ finding = json['finding'] != null ? Finding.fromJson(json['finding']) : null;
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ if (finding != null) {
+ data['finding'] = finding!.toJson();
+ }
+ return data;
+ }
+}
+
+class Finding {
+ int? id;
+ String? name;
+ int? value;
+
+ Finding({this.id, this.name, this.value});
+
+ Finding.fromJson(Map json) {
+ id = json['id'];
+ name = json['name'];
+ value = json['value'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['name'] = name;
+ data['value'] = value;
+ return data;
+ }
+}
diff --git a/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart
new file mode 100644
index 00000000..e6a79e91
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart
@@ -0,0 +1,41 @@
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/models/device/asset.dart';
+import 'package:test_sa/models/fault_description.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+
+class EquipmentInternalAuditFormModel {
+ int? id=0;
+ String? deviceArName;
+ String? auditorId;
+ String? woOrderNo;
+ List? devicePhotos;
+ List findings =[];
+ List attachments = [];
+ String? remarks;
+ Asset? device;
+ EquipmentInternalAuditFormModel({
+ this.id,
+ this.deviceArName,
+ this.auditorId,
+ this.devicePhotos,
+ this.woOrderNo,
+ this.remarks,
+ });
+
+ Map toJson() {
+ return {
+ 'id': id??0,
+ 'assetId': device?.id,
+ 'auditorId': auditorId,
+ 'findings': findings.map((e) => {'findingId': e.value}).toList(),
+ 'attachments': attachments.map((e) => e.toJson()).toList(),
+ 'remarks': remarks,
+ };
+ }
+
+
+}
\ No newline at end of file
diff --git a/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart
new file mode 100644
index 00000000..5e21d5ae
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/internal_audit_attachment_model.dart
@@ -0,0 +1,27 @@
+import 'dart:developer';
+
+class InternalAuditAttachments {
+ InternalAuditAttachments({this.id, this.originalName, this.name, this.createdBy});
+
+ int? id;
+ String? name;
+ String? originalName;
+ String? createdBy;
+
+ InternalAuditAttachments.fromJson(Map json) {
+ log('name is ${json['name']}');
+ id = json['id'];
+ name = (json['name'] != null && !json['name'].toString().startsWith('data:image/jpeg')) ? json['name'] : null;
+ originalName = json['originalName'];
+ createdBy = json['createdBy'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['name'] = name;
+ data['originalName'] = originalName;
+ // data['createdBy'] = createdBy;
+ return data;
+ }
+}
diff --git a/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart
new file mode 100644
index 00000000..708ab2d1
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/internal_audit_timer_model.dart
@@ -0,0 +1,35 @@
+class InternalAuditTimerModel {
+ int? id;
+ String? startDate;
+ String? endDate;
+ double? totalWorkingHour;
+ String? comment;
+
+ InternalAuditTimerModel({
+ this.id,
+ this.startDate,
+ this.endDate,
+ this.totalWorkingHour,
+ this.comment,
+ });
+
+ factory InternalAuditTimerModel.fromJson(Map json) {
+ return InternalAuditTimerModel(
+ id: json['id'] as int?,
+ startDate: json['startDate'],
+ endDate: json['endDate'],
+ totalWorkingHour: (json['totalWorkingHours'] as num?)?.toDouble(),
+ comment: json['comment'] as String?,
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'startDate': startDate,
+ 'endDate': endDate,
+ 'totalWorkingHours': totalWorkingHour,
+ 'comment': comment,
+ };
+ }
+}
\ No newline at end of file
diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart
new file mode 100644
index 00000000..0546ccdc
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/system_internal_audit_data_model.dart
@@ -0,0 +1,138 @@
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/internal_audit_module/models/engineer_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart';
+
+class SystemInternalAuditDataModel {
+ int? id;
+ int? assetGroupId;
+ String? requestNo;
+ int? requestNoSequence;
+ Auditor? auditor;
+ Lookup? status;
+ Lookup? findingType;
+ String? findingDescription;
+ Lookup? workOrderType;
+ Auditor? assignEmployee;
+ SystemAuditWorkOrderDetailModel? workOrderDetails; // Already exists as a separate model
+ String? createdBy;
+ String? createdDate;
+ String? modifiedBy;
+ String? modifiedDate;
+ List? attachments;
+ EngineerData? engineerData;
+
+ SystemInternalAuditDataModel({
+ this.id,
+ this.assetGroupId,
+ this.requestNo,
+ this.requestNoSequence,
+ this.auditor,
+ this.status,
+ this.findingType,
+ this.findingDescription,
+ this.workOrderType,
+ this.assignEmployee,
+ this.workOrderDetails,
+ this.createdBy,
+ this.createdDate,
+ this.modifiedBy,
+ this.modifiedDate,
+ this.attachments,
+ this.engineerData,
+ });
+
+ SystemInternalAuditDataModel.fromJson(Map json) {
+ id = json['id'];
+ assetGroupId = json['assetGroupId'];
+ requestNo = json['requestNo'];
+ requestNoSequence = json['requestNoSequence'];
+ auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null;
+ status = json['status'] != null ? Lookup.fromJson(json['status']) : null;
+ findingType = json['findingType'] != null ? Lookup.fromJson(json['findingType']) : null;
+ findingDescription = json['findingDescription'];
+ workOrderType = json['workOrderType'] != null ? Lookup.fromJson(json['workOrderType']) : null;
+ assignEmployee = json['assignEmployee'] != null ? Auditor.fromJson(json['assignEmployee']) : null;
+ workOrderDetails = json['workOrderDetails'] != null ? SystemAuditWorkOrderDetailModel.fromJson(json['workOrderDetails']) : null; // Keep as-is
+ createdBy = json['createdBy'];
+ createdDate = json['createdDate'];
+ modifiedBy = json['modifiedBy'];
+ modifiedDate = json['modifiedDate'];
+ attachments = json['attachments'] != null
+ ? (json['attachments'] as List)
+ .map((e) => InternalAuditAttachments.fromJson(e))
+ .where((e) => e.name != null) // optional filter if you want to skip null names
+ .toList()
+ : [];
+ engineerData = json['engineerData'] != null ? EngineerData.fromJson(json['engineerData']) : null;
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['assetGroupId'] = assetGroupId;
+ data['requestNo'] = requestNo;
+ data['requestNoSequence'] = requestNoSequence;
+ if (auditor != null) data['auditor'] = auditor!.toJson();
+ if (status != null) data['status'] = status!.toJson();
+ if (findingType != null) data['findingType'] = findingType!.toJson();
+ data['findingDescription'] = findingDescription;
+ if (workOrderType != null) data['workOrderType'] = workOrderType!.toJson();
+ if (assignEmployee != null) data['assignEmployee'] = assignEmployee!.toJson();
+ data['workOrderDetails'] = workOrderDetails;
+ data['createdBy'] = createdBy;
+ data['createdDate'] = createdDate;
+ data['modifiedBy'] = modifiedBy;
+ data['modifiedDate'] = modifiedDate;
+ if (engineerData != null) data['engineerData'] = engineerData!.toJson();
+ return data;
+ }
+}
+
+class Auditor {
+ String? userId;
+ String? userName;
+ String? email;
+ String? employeeId;
+ int? languageId;
+ String? extensionNo;
+ String? phoneNumber;
+ bool? isActive;
+
+ Auditor({
+ this.userId,
+ this.userName,
+ this.email,
+ this.employeeId,
+ this.languageId,
+ this.extensionNo,
+ this.phoneNumber,
+ this.isActive,
+ });
+
+ Auditor.fromJson(Map json) {
+ userId = json['userId'];
+ userName = json['userName'];
+ email = json['email'];
+ employeeId = json['employeeId'];
+ languageId = json['languageId'];
+ extensionNo = json['extensionNo'];
+ phoneNumber = json['phoneNumber'];
+ isActive = json['isActive'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['userId'] = userId;
+ data['userName'] = userName;
+ data['email'] = email;
+ data['employeeId'] = employeeId;
+ data['languageId'] = languageId;
+ data['extensionNo'] = extensionNo;
+ data['phoneNumber'] = phoneNumber;
+ data['isActive'] = isActive;
+ return data;
+ }
+}
+
+
diff --git a/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart
new file mode 100644
index 00000000..3fda34d0
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/system_internal_audit_form_model.dart
@@ -0,0 +1,202 @@
+import 'dart:developer';
+
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+
+class SystemInternalAuditFormModel {
+ int? id;
+ String? auditorId;
+ String? assignEmployeeId;
+ Lookup? findingType;
+ String? findingDescription;
+ Lookup? workOrderType;
+ int? correctiveMaintenanceId;
+ int? planPreventiveVisitId;
+ int? assetTransferId;
+ List? attachments = [];
+ int? taskJobId;
+ int? taskAlertJobId;
+ int? gasRefillId;
+ int? planRecurrentTaskId;
+ int? statusId;
+ SystemAuditWorkOrderDetailModel? workOrderDetailModel;
+
+ SystemInternalAuditFormModel({
+ this.id,
+ this.auditorId,
+ this.assignEmployeeId,
+ this.findingType,
+ this.findingDescription,
+ this.workOrderType,
+ this.correctiveMaintenanceId,
+ this.planPreventiveVisitId,
+ this.assetTransferId,
+ this.taskJobId,
+ this.taskAlertJobId,
+ this.gasRefillId,
+ this.planRecurrentTaskId,
+ this.workOrderDetailModel,
+ this.statusId,
+ this.attachments,
+ });
+
+ Map toJson() {
+ return {
+ // 'id': id,
+ 'auditorId': auditorId,
+ 'assignEmployeeId': assignEmployeeId,
+ 'findingTypeId': findingType?.id,
+ 'findingDescription': findingDescription,
+ 'workOrderTypeId': workOrderType?.id,
+ 'correctiveMaintenanceId': correctiveMaintenanceId,
+ 'planPreventiveVisitId': planPreventiveVisitId,
+ 'assetTransferId': assetTransferId,
+ 'taskJobId': taskJobId,
+ 'taskAlertJobId': taskAlertJobId,
+ 'gasRefillId': gasRefillId,
+ 'planRecurrentTaskId': planRecurrentTaskId,
+ 'statusId': statusId,
+ 'attachments': attachments?.map((e) => e.toJson()).toList(),
+ };
+ }
+}
+
+class WoAutoCompleteModel {
+ int? id;
+ String? workOrderNo;
+ String? displayName;
+
+ WoAutoCompleteModel({this.id, this.workOrderNo, this.displayName});
+
+ WoAutoCompleteModel.fromJson(Map json) {
+ id = json['id'];
+ workOrderNo = json['workOrderNo'];
+ displayName = json['workOrderNo'];
+ }
+
+ Map toJson() {
+ final Map data = {};
+ data['id'] = id;
+ data['woOrderNo'] = workOrderNo;
+ data['displayName'] = workOrderNo;
+ return data;
+ }
+}
+
+class SystemAuditWorkOrderDetailModel {
+ String? createdBy;
+ DateTime? createdDate;
+ String? modifiedBy;
+ DateTime? modifiedDate;
+ int? id;
+ String? workOrderNo;
+ String? woAssignedEngineer;
+ String? woAssetNo;
+ String? wosn;
+ String? woAssetName;
+ String? woModel;
+ String? woManufacturer;
+ String? woSite;
+ String? woDepartment;
+ String? wOPMScheduleDate;
+ String? wOPMActualVisitDate;
+ String? wOAssetTransferDestinationSite;
+ String? wOAssetTransferSenderEngineer;
+ String? wOAssetTransferReceiverEngineer;
+ String? wOTaskAlertJobImpactedStatus;
+ String? wOTaskAlertJobAcknowledgment;
+ String? wOGasRefillType;
+ String? wORecurrentTaskTaskType;
+ String? wORecurrentTaskPlanNo;
+ String? wORecurrentTaskPlanName;
+ String? wORecurrentTaskStatus;
+
+ SystemAuditWorkOrderDetailModel({
+ this.createdBy,
+ this.createdDate,
+ this.modifiedBy,
+ this.modifiedDate,
+ this.id,
+ this.workOrderNo,
+ this.woAssignedEngineer,
+ this.woAssetNo,
+ this.wosn,
+ this.woAssetName,
+ this.woModel,
+ this.woManufacturer,
+ this.woSite,
+ this.woDepartment,
+ this.wOPMScheduleDate,
+ this.wOPMActualVisitDate,
+ this.wOAssetTransferDestinationSite,
+ this.wOAssetTransferSenderEngineer,
+ this.wOAssetTransferReceiverEngineer,
+ this.wOTaskAlertJobImpactedStatus,
+ this.wOTaskAlertJobAcknowledgment,
+ this.wOGasRefillType,
+ this.wORecurrentTaskTaskType,
+ this.wORecurrentTaskPlanNo,
+ this.wORecurrentTaskPlanName,
+ this.wORecurrentTaskStatus,
+ });
+
+ SystemAuditWorkOrderDetailModel.fromJson(Map json) {
+ createdBy = json['createdBy'];
+ createdDate = json['createdDate'] != null ? DateTime.tryParse(json['createdDate']) : null;
+ modifiedBy = json['modifiedBy'];
+ modifiedDate = json['modifiedDate'] != null ? DateTime.tryParse(json['modifiedDate']) : null;
+ id = json['id'];
+ workOrderNo = json['workOrderNo'];
+ woAssignedEngineer = json['woAssignedEngineer'];
+ woAssetNo = json['woAssetNo'];
+ wosn = json['wosn'];
+ woAssetName = json['woAssetName'];
+ woModel = json['woModel'];
+ woManufacturer = json['woManufacturer'];
+ woSite = json['woSite'];
+ woDepartment = json['woDepartment'];
+ wOPMScheduleDate = json['wO_PM_ScheduleDate'];
+ wOPMActualVisitDate = json['wO_PM_ActualVisitDate'];
+ wOAssetTransferDestinationSite = json['wO_AssetTransfer_DestinationSite'];
+ wOAssetTransferSenderEngineer = json['wO_AssetTransfer_SenderEngineer'];
+ wOAssetTransferReceiverEngineer = json['wO_AssetTransfer_ReceiverEngineer'];
+ wOTaskAlertJobImpactedStatus = json['wO_TaskAlertJob_ImpactedStatus'];
+ wOTaskAlertJobAcknowledgment = json['wO_TaskAlertJob_Acknowledgment'];
+ wOGasRefillType = json['wO_GasRefill_Type'];
+ wORecurrentTaskTaskType = json['wO_RecurrentTask_TaskType'];
+ wORecurrentTaskPlanNo = json['wO_RecurrentTask_PlanNo'];
+ wORecurrentTaskPlanName = json['wO_RecurrentTask_PlanName'];
+ wORecurrentTaskStatus = json['wO_RecurrentTask_Status'];
+ }
+
+ Map toJson() {
+ return {
+ 'createdBy': createdBy,
+ 'createdDate': createdDate?.toIso8601String(),
+ 'modifiedBy': modifiedBy,
+ 'modifiedDate': modifiedDate?.toIso8601String(),
+ 'id': id,
+ 'workOrderNo': workOrderNo,
+ 'woAssignedEngineer': woAssignedEngineer,
+ 'woAssetNo': woAssetNo,
+ 'wosn': wosn,
+ 'woAssetName': woAssetName,
+ 'woModel': woModel,
+ 'woManufacturer': woManufacturer,
+ 'woSite': woSite,
+ 'woDepartment': woDepartment,
+ 'wO_PM_ScheduleDate': wOPMScheduleDate,
+ 'wO_PM_ActualVisitDate': wOPMActualVisitDate,
+ 'wO_AssetTransfer_DestinationSite': wOAssetTransferDestinationSite,
+ 'wO_AssetTransfer_SenderEngineer': wOAssetTransferSenderEngineer,
+ 'wO_AssetTransfer_ReceiverEngineer': wOAssetTransferReceiverEngineer,
+ 'wO_TaskAlertJob_ImpactedStatus': wOTaskAlertJobImpactedStatus,
+ 'wO_TaskAlertJob_Acknowledgment': wOTaskAlertJobAcknowledgment,
+ 'wO_GasRefill_Type': wOGasRefillType,
+ 'wO_RecurrentTask_TaskType': wORecurrentTaskTaskType,
+ 'wO_RecurrentTask_PlanNo': wORecurrentTaskPlanNo,
+ 'wO_RecurrentTask_PlanName': wORecurrentTaskPlanName,
+ 'wO_RecurrentTask_Status': wORecurrentTaskStatus,
+ };
+ }
+}
diff --git a/lib/modules/internal_audit_module/models/update_audit_form_model.dart b/lib/modules/internal_audit_module/models/update_audit_form_model.dart
new file mode 100644
index 00000000..6942d51f
--- /dev/null
+++ b/lib/modules/internal_audit_module/models/update_audit_form_model.dart
@@ -0,0 +1,61 @@
+import 'package:test_sa/models/timer_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart';
+
+class AuditFormModel {
+ int? id;
+ String? createdDate;
+ int? requestId;
+ String? debrief;
+ DateTime? startTime;
+ DateTime? endTime;
+ double? totalHours;
+ List? attachments;
+ bool? isComplete;
+ TimerModel? auditTimerModel = TimerModel();
+ List? auditTimers = [];
+ TimerModel? auditTimePicker;
+ List? timerModelList = [];
+
+ AuditFormModel(
+ {this.id,
+ this.requestId,
+ this.debrief,
+ this.startTime,
+ this.endTime,
+ this.totalHours,
+ this.createdDate,
+ this.attachments,
+ this.isComplete,
+ this.auditTimerModel,
+ this.timerModelList,
+ this.auditTimePicker,
+ this.auditTimers});
+
+ AuditFormModel.fromJson(Map json) {
+ id = json['id'];
+ requestId = json['requestId'];
+ debrief = json['debrief'];
+ startTime = json['startTime'] != null ? DateTime.tryParse(json['startTime']) : null;
+ endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null;
+ totalHours = json['totalHours']?.toDouble();
+ if (json['attachments'] != null) {
+ attachments = (json['attachments'] as List).map((e) => InternalAuditAttachments.fromJson(e)).toList();
+ }
+ isComplete = json['isComplete'];
+ }
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'requestId': requestId,
+ 'debrief': debrief,
+ 'startTime': startTime?.toIso8601String(),
+ 'endTime': endTime?.toIso8601String(),
+ // 'auditTimer': auditTimers,
+ 'totalHours': totalHours,
+ 'attachments': attachments?.map((e) => e.toJson()).toList(),
+ 'isComplete': isComplete,
+ };
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart
new file mode 100644
index 00000000..532a5b14
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart
@@ -0,0 +1,147 @@
+import 'dart:convert';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/generic_attachment_model.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart';
+import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
+import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
+
+class CreateEquipmentInternalAuditForm extends StatefulWidget {
+ static const String id = "/create-equipment-internal-audit-form";
+
+ const CreateEquipmentInternalAuditForm({Key? key}) : super(key: key);
+
+ @override
+ _CreateEquipmentInternalAuditFormState createState() => _CreateEquipmentInternalAuditFormState();
+}
+
+class _CreateEquipmentInternalAuditFormState extends State with TickerProviderStateMixin {
+ late TextEditingController _commentController;
+ final EquipmentInternalAuditFormModel _equipmentinternalAuditModel = EquipmentInternalAuditFormModel();
+ final List _attachments = [];
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ FocusNode auditCheckListNode = FocusNode();
+
+ @override
+ void initState() {
+ super.initState();
+ _commentController = TextEditingController();
+ }
+
+ @override
+ void dispose() {
+ _commentController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(title: 'Equipment Internal Audit Checklist'.addTranslation),
+ body: Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ AssetPicker(
+ device: _equipmentinternalAuditModel.device,
+ borderColor: AppColor.black20,
+ buttonColor: AppColor.white936,
+ onPick: (asset) async {
+ _equipmentinternalAuditModel.device = asset;
+ setState(() {});
+ },
+ ),
+ 16.height,
+ //TODO need to check layout issue...
+ MultipleItemDropDownMenu(
+ context: context,
+ showAsBottomSheet: true,
+ backgroundColor: AppColor.neutral100,
+ showShadow: false,
+ showCancel: true,
+ requestById: context.userProvider.user?.clientId,
+ title: 'Internal Audit Checklist'.addTranslation,
+ initialValue: _equipmentinternalAuditModel.findings,
+ onSelect: (value) {
+ _equipmentinternalAuditModel.findings = value ?? [];
+ },
+ ),
+ 16.height,
+ AppTextFormField(
+ backgroundColor: AppColor.fieldBgColor(context),
+ labelText: 'Remarks'.addTranslation,
+ labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
+ alignLabelWithHint: true,
+ textInputType: TextInputType.multiline,
+ showShadow: false,
+ onSaved: (value) {
+ _equipmentinternalAuditModel.remarks = value;
+ },
+ ),
+ 16.height,
+ AttachmentPicker(
+ label: context.translation.attachments,
+ attachment: _attachments,
+ buttonColor: AppColor.primary10,
+ onlyImages: false,
+ onChange: (value) {},
+ buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10),
+ ),
+ ],
+ ).toShadowContainer(context),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(label: context.translation.submitRequest, buttonColor: AppColor.primary10, onPressed: _submit),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Future _submit() async {
+ InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false);
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save();
+ _equipmentinternalAuditModel.attachments = [];
+ for (var item in _attachments) {
+ String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
+ _equipmentinternalAuditModel.attachments.add(InternalAuditAttachments(id: item.id, name: fileName));
+ }
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ _equipmentinternalAuditModel.auditorId = context.userProvider.user?.userID;
+ bool status = await internalAuditProvider.addEquipmentInternalAudit(context: context, request: _equipmentinternalAuditModel);
+ Navigator.pop(context);
+ if(status){
+ Navigator.pop(context);
+ }
+ }
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart
new file mode 100644
index 00000000..9d18f9fd
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart
@@ -0,0 +1,207 @@
+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/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/views/widgets/images/files_list.dart';
+import 'package:test_sa/views/widgets/loaders/app_loading.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+
+class EquipmentInternalAuditDetailPage extends StatefulWidget {
+ static const String id = "/details-internal-audit";
+
+ final int auditId;
+
+ const EquipmentInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key);
+
+ @override
+ _EquipmentInternalAuditDetailPageState createState() {
+ return _EquipmentInternalAuditDetailPageState();
+ }
+}
+
+class _EquipmentInternalAuditDetailPageState extends State {
+ bool isWoType = true;
+ EquipmentInternalAuditDataModel? model;
+ late InternalAuditProvider _internalAuditProvider;
+ List allAttachments = [];
+
+ @override
+ void initState() {
+ super.initState();
+ _internalAuditProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getAuditData();
+ });
+ }
+
+ Future getAuditData() async {
+ model = await _internalAuditProvider.getEquipmentInternalAuditById(widget.auditId);
+ allAttachments.clear();
+ allAttachments = [
+ ...(model?.attachments ?? []),
+ ...(model?.engineerData?.attachments ?? []),
+ ];
+
+
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ //TODO need to check when implementing provider needed or not .
+ return Scaffold(
+ appBar: const DefaultAppBar(title: "Request Details"),
+ body: Selector(
+ selector: (_, provider) => provider.isLoading,
+ builder: (_, isLoading, __) {
+ if (isLoading) return const ALoading();
+ if (model == null) return NoDataFound(message: context.translation.noDataFound).center;
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ assetDetails(),
+ 8.height,
+ requestDetails(),
+ 8.height,
+ if (model?.remarks?.isNotEmpty ?? false) ...[
+ const Divider().defaultStyle(context),
+ model!.remarks!.bodyText(context),
+ 8.height,
+ ],
+ if (allAttachments.isNotEmpty) ...[
+ const Divider().defaultStyle(context),
+ Text(
+ "Attachments".addTranslation,
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 8.height,
+ FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []),
+ ],
+ ],
+ ).paddingAll(0).toShadowContainer(context),
+ ).expanded,
+ if (context.userProvider.isEngineer)
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: "Update",
+ onPressed: () async {
+ final result = await Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (_) => UpdateEquipmentInternalAuditPage(model: model),
+ ),
+ );
+ if (result == true) {
+ await getAuditData();
+ setState(() {}); // refresh UI with new model
+ }
+ // Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdateEquipmentInternalAuditPage(model: model)));
+ }),
+ ),
+ ],
+ );
+ },
+ ));
+ }
+
+ Widget workOrderInformation() {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Divider().defaultStyle(context),
+ Text(
+ "WO Info",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ '${context.translation.woNumber}: ${'-'}'.bodyText(context),
+ '${'WO Type'.addTranslation}: ${'-'}'.bodyText(context),
+ '${context.translation.site}: ${'-'}'.bodyText(context),
+ '${context.translation.assetName}: ${'-'}'.bodyText(context),
+ '${context.translation.manufacture}: ${'-'}'.bodyText(context),
+ '${context.translation.model}: ${'-'}'.bodyText(context),
+ ],
+ );
+ }
+
+ Widget requestDetails() {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Divider().defaultStyle(context),
+ Text(
+ "Request Details",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ if (model != null && model!.equipmentsFindings != null && model!.equipmentsFindings!.isNotEmpty)
+ ...model!.equipmentsFindings!.map((item) {
+ final findingName = item.finding?.name ?? 'Unknown';
+ return checklistWidget(value: findingName.addTranslation);
+ }).toList()
+ else
+ Text('No findings available'.addTranslation),
+ ],
+ );
+ }
+
+ Widget assetDetails() {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Asset Details",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ '${context.translation.assetName}: ${model?.asset?.assetName ?? '-'}'.bodyText(context),
+ '${context.translation.assetNo}: ${model?.asset?.assetNumber ?? '-'}'.bodyText(context),
+ '${context.translation.manufacture}: ${model?.asset?.manufacturerName ?? '-'}'.bodyText(context),
+ '${context.translation.model}: ${model?.asset?.modelName ?? '-'}'.bodyText(context),
+ ],
+ );
+ }
+
+ Widget checklistWidget({required String value}) {
+ return Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Checkbox(
+ value: true,
+ activeColor: AppColor.neutral120,
+ materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ visualDensity: const VisualDensity(horizontal: -4, vertical: -3),
+ onChanged: (value) {},
+ ),
+ value.bodyText(context),
+ ],
+ );
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart
new file mode 100644
index 00000000..a17407a2
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart
@@ -0,0 +1,115 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/all_requests_and_count_model.dart';
+import 'package:test_sa/models/new_models/dashboard_detail.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class EquipmentInternalAuditItemView extends StatelessWidget {
+ final Data? requestData;
+ final RequestsDetails? requestDetails;
+ final bool showShadow;
+
+ const EquipmentInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ //TODO need to refactor this code repetation @waseem
+ if (requestData != null) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StatusLabel(
+ label: requestData!.statusName!,
+ textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
+ backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!),
+ ),
+ 1.width.expanded,
+ Text(
+ requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
+ textAlign: TextAlign.end,
+ style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
+ ),
+ ],
+ ),
+ 8.height,
+ (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context),
+ infoWidget(label: context.translation.assetNumber, value: requestData?.assetNumber, context: context),
+
+ 8.height,
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.translation.viewDetails,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
+ ),
+ 4.width,
+ Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
+ ],
+ ),
+ ],
+ ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
+ Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!)));
+ });
+ }
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StatusLabel(
+ label: requestDetails!.status!,
+ textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
+ backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!),
+ ),
+ 1.width.expanded,
+ Text(
+ requestDetails!.date?.toServiceRequestCardFormat ?? "",
+ textAlign: TextAlign.end,
+ style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
+ ),
+ ],
+ ),
+ 8.height,
+ (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context),
+ 8.height,
+ infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context),
+ infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context),
+ infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
+ 8.height,
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.translation.viewDetails,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
+ ),
+ 4.width,
+ Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
+ ],
+ ),
+ ],
+ ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
+ Navigator.push(context, MaterialPageRoute(builder: (context) => EquipmentInternalAuditDetailPage(auditId: requestDetails!.id!)));
+ });
+ }
+
+ Widget infoWidget({required String label, String? value, required BuildContext context}) {
+ if (value != null && value.isNotEmpty) {
+ return '$label: $value'.bodyText(context);
+ }
+ return const SizedBox();
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart
new file mode 100644
index 00000000..f69e4a10
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart
@@ -0,0 +1,322 @@
+import 'dart:convert';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/generic_attachment_model.dart';
+import 'package:test_sa/models/timer_model.dart';
+import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
+import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
+import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
+import 'package:test_sa/views/widgets/timer/app_timer.dart';
+import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
+
+class UpdateEquipmentInternalAuditPage extends StatefulWidget {
+ static const String id = "update-equipment-internal-audit";
+ EquipmentInternalAuditDataModel? model;
+
+ UpdateEquipmentInternalAuditPage({Key? key, this.model}) : super(key: key);
+
+ @override
+ State createState() => _UpdateEquipmentInternalAuditPageState();
+}
+
+class _UpdateEquipmentInternalAuditPageState extends State {
+ final bool _isLoading = false;
+ double totalWorkingHours = 0.0;
+ AuditFormModel formModel = AuditFormModel();
+ final TextEditingController _workingHoursController = TextEditingController();
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ List _attachments = [];
+
+ //TODO need to check if it's needed or not..
+ List timerList = [];
+
+ @override
+ void initState() {
+ populateForm();
+ super.initState();
+ }
+
+ void populateForm() {
+ formModel.requestId = widget.model?.id;
+ formModel.id = widget.model?.id;
+ _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? [];
+
+ calculateWorkingTime();
+ }
+
+ void calculateWorkingTime() {
+ final helperModel = formModel;
+ final timers = helperModel.auditTimers ?? [];
+ totalWorkingHours = timers.fold(0.0, (sum, item) {
+ if (item.startDate == null || item.endDate == null) return sum;
+ try {
+ final start = DateTime.parse(item.startDate!);
+ final end = DateTime.parse(item.endDate!);
+ final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
+ return sum + diffInHours;
+ } catch (_) {
+ return sum;
+ }
+ });
+ timerList = timers.map((e) {
+ return TimerHistoryModel(
+ id: e.id,
+ startTime: e.startDate,
+ endTime: e.endDate,
+ workingHours: e.startDate,
+ );
+ }).toList();
+ }
+
+ _onSubmit(BuildContext context) async {
+ bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
+ InternalAuditProvider provider = Provider.of(context, listen: false);
+
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ formModel.auditTimers ??= [];
+ if (formModel.auditTimePicker != null) {
+ int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds;
+ formModel.auditTimers?.add(
+ InternalAuditTimerModel(
+ id: 0,
+ startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null
+ endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null
+ totalWorkingHour: ((durationInSecond) / 60 / 60),
+ ),
+ );
+ }
+ formModel.timerModelList?.forEach((timer) {
+ int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
+ formModel.auditTimers?.add(
+ InternalAuditTimerModel(
+ id: 0,
+ startDate: timer.startAt!.toIso8601String(), // Handle potential null
+ endDate: timer.endAt?.toIso8601String(), // Handle potential null
+ totalWorkingHour: ((durationInSecond) / 60 / 60),
+ ),
+ );
+ });
+
+ _formKey.currentState!.save();
+ formModel.attachments = [];
+ for (var item in _attachments) {
+ String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
+ formModel.attachments!.add(
+ InternalAuditAttachments(
+ id: item.id,
+ originalName: fileName,
+ name: fileName,
+ ),
+ );
+ }
+ final success = await provider.updateEquipmentInternalAudit(model: formModel);
+ Navigator.pop(context);
+ if (formModel.isComplete == true) {
+ //Navigate to List screen.
+ } else if (formModel.isComplete == false) {
+ //Navigate to Detail screen.
+ if (success) {
+ Navigator.of(context).pop(true);
+ } else {
+ Fluttertoast.showToast(msg: 'Failed to update');
+ }
+
+ }
+ }
+
+ @override
+ void dispose() {
+ _workingHoursController.dispose();
+ super.dispose();
+ }
+
+ void updateTimer({TimerModel? timer}) {
+ if (timer?.startAt != null && timer?.endAt != null) {
+ final start = timer!.startAt!;
+ final end = timer.endAt!;
+
+ final difference = end.difference(start);
+ final totalHours = difference.inSeconds / 3600.0;
+ formModel.startTime = start;
+ formModel.endTime = end;
+ formModel.totalHours = totalHours;
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: DefaultAppBar(
+ title: 'Update Information'.addTranslation,
+ onWillPopScope: () {
+ formModel.isComplete = false;
+ _onSubmit(context);
+ },
+ ),
+ key: _scaffoldKey,
+ body: Form(
+ key: _formKey,
+ child: LoadingManager(
+ isLoading: _isLoading,
+ isFailedLoading: false,
+ stateCode: 200,
+ onRefresh: () async {},
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ 8.height,
+ AppTextFormField(
+ labelText: 'Debrief'.addTranslation,
+ textInputType: TextInputType.multiline,
+ hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
+ labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
+ alignLabelWithHint: true,
+ initialValue: formModel.debrief,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showShadow: false,
+ onSaved: (value) {
+ formModel.debrief = value;
+ },
+ ),
+ 8.height,
+ _timerWidget(context, totalWorkingHours),
+ 16.height,
+ AttachmentPicker(
+ label: 'Upload Attachment',
+ attachment: _attachments,
+ buttonColor: AppColor.primary10,
+ onlyImages: false,
+ buttonIcon: 'attachment_icon'.toSvgAsset(
+ color: AppColor.primary10,
+ ),
+ ),
+ 8.height,
+ ],
+ ).toShadowContainer(context),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ AppFilledButton(
+ label: context.translation.save,
+ buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60,
+ textColor: context.isDark ? AppColor.white10 : AppColor.black10,
+ onPressed: () {
+ formModel.isComplete = false;
+ _onSubmit(context);
+ }).expanded,
+ 12.width,
+ AppFilledButton(
+ label: context.translation.complete,
+ buttonColor: AppColor.primary10,
+ onPressed: () {
+ formModel.isComplete = true;
+ _onSubmit(context);
+ }).expanded,
+ ],
+ ),
+ ),
+ ],
+ )),
+ ),
+ ).handlePopScope(
+ cxt: context,
+ onSave: () {
+ formModel.isComplete = false;
+ _onSubmit(context);
+ });
+ }
+
+ Widget _timerWidget(BuildContext context, double totalWorkingHours) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ //TODO multiple timer ..
+ // AppTimer(
+ // label: context.translation.timer,
+ // timer: formModel.auditTimerModel,
+ // // enabled: enableTimer,
+ // pickerTimer: formModel.auditTimePicker,
+ // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''),
+ // onPick: (time) {
+ // formModel.auditTimePicker = time;
+ // setState(() {});
+ // log('Time picker start ${formModel.auditTimePicker?.startAt}');
+ // log('Time picker end ${formModel.auditTimePicker?.endAt}');
+ // },
+ // timerProgress: (isRunning) {},
+ // onChange: (timer) async {
+ // formModel.auditTimerModel = timer;
+ // log('start ${formModel.auditTimerModel?.startAt}');
+ // log('end ${formModel.auditTimerModel?.endAt}');
+ // if (timer.startAt != null && timer.endAt != null) {
+ // formModel.timerModelList = formModel.timerModelList ?? [];
+ // formModel.timerModelList!.add(timer);
+ // }
+ // setState(() {});
+ // log('list length ${formModel.timerModelList?.length}');
+ // return true;
+ // },
+ // ),
+ AppTimer(
+ label: context.translation.workingHours,
+ timer: formModel.auditTimerModel,
+ pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''),
+ pickerTimer: formModel.auditTimePicker,
+ showPicker: false,
+ onPick: (timer) {
+ updateTimer(timer: timer);
+ },
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: AppColor.fieldBgColor(context),
+ borderRadius: BorderRadius.circular(10),
+ ),
+ timerProgress: (isRunning) {},
+ onChange: (timer) async {
+ updateTimer(timer: timer);
+ log('here onChange ${timer.startAt}');
+
+ return true;
+ },
+ ),
+ if (totalWorkingHours > 0.0) ...[
+ 12.height,
+ WorkingTimeTile(
+ timerList: timerList,
+ totalWorkingTime: totalWorkingHours,
+ ),
+ ],
+ ],
+ );
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart
new file mode 100644
index 00000000..20ab2451
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/system_internal_audit/create_system_internal_audit_form.dart
@@ -0,0 +1,278 @@
+import 'dart:convert';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/device/asset.dart';
+import 'package:test_sa/models/generic_attachment_model.dart';
+import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
+import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
+import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
+import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
+import '../../../../../../../new_views/common_widgets/default_app_bar.dart';
+
+class CreateSystemInternalAuditForm extends StatefulWidget {
+ static const String id = "/create-system-audit-view";
+
+ const CreateSystemInternalAuditForm({Key? key}) : super(key: key);
+
+ @override
+ _CreateSystemInternalAuditFormState createState() => _CreateSystemInternalAuditFormState();
+}
+//TODO remove unnecessary code
+
+class _CreateSystemInternalAuditFormState extends State with TickerProviderStateMixin {
+ late TextEditingController _commentController;
+ late InternalAuditProvider _internalAuditProvider;
+ final SystemInternalAuditFormModel _model = SystemInternalAuditFormModel();
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ final List _attachments = [];
+ late TextEditingController _woAutoCompleteController;
+ bool showLoading = false;
+
+ @override
+ void initState() {
+ super.initState();
+ _commentController = TextEditingController();
+ _woAutoCompleteController = TextEditingController();
+ _internalAuditProvider = Provider.of(context, listen: false);
+ }
+
+ @override
+ void dispose() {
+ _commentController.dispose();
+ _woAutoCompleteController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: DefaultAppBar(title: 'System Internal Audit Checklist'.addTranslation),
+ body: Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Wo Type'.addTranslation,
+ showShadow: false,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ initialValue: _model.workOrderType,
+ onSelect: (status) {
+ if (status != null) {
+ _model.workOrderType = status;
+ _model.workOrderDetailModel = SystemAuditWorkOrderDetailModel();
+ _clearWorkOrderSelectionIds();
+ _woAutoCompleteController.clear();
+ setState(() {});
+ }
+ },
+ ),
+ 12.height,
+ SystemAuditWoAutoCompleteField(
+ woTypeId: _model.workOrderType?.value,
+ controller: _woAutoCompleteController,
+ clearAfterPick: false,
+ initialValue: '',
+ onPick: (wo) async {
+ InternalAuditProvider provider = Provider.of(context, listen: false);
+ setState(() {
+ showLoading = true;
+ });
+ _model.workOrderDetailModel = await provider.loadAllWorkOrderDetailsByID(workOrderId: wo.id!, workOrderTypeId: _model.workOrderType!.value!);
+ updateWorkOrderReference(woTypeId: _model.workOrderType?.value, selectedId: wo.id);
+
+ setState(() {
+ showLoading = false;
+ });
+ },
+ ),
+ 12.height,
+ // if(_internalAuditModel.woOrderNo!=null)
+ _workOrderInfoWidget(context),
+ 12.height,
+ SingleItemDropDownMenu(
+ context: context,
+ height: 56.toScreenHeight,
+ title: 'Finding Type'.addTranslation,
+ showShadow: false,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showAsBottomSheet: true,
+ initialValue: _model.findingType,
+ onSelect: (status) {
+ if (status != null) {
+ _model.findingType = status;
+ setState(() {});
+ }
+ },
+ ),
+ 12.height,
+ AppTextFormField(
+ backgroundColor: AppColor.fieldBgColor(context),
+ labelText: 'Finding Description'.addTranslation,
+ labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
+ alignLabelWithHint: true,
+ textInputType: TextInputType.multiline,
+ showShadow: false,
+ onSaved: (value) {
+ _model.findingDescription = value;
+ },
+ ),
+ 16.height,
+ AttachmentPicker(
+ label: context.translation.attachments,
+ attachment: _attachments,
+ buttonColor: AppColor.primary10,
+ onlyImages: false,
+ buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10),
+ ),
+ ],
+ ).toShadowContainer(context),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: context.translation.submitRequest,
+ onPressed: _submit,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Future _submit() async {
+ InternalAuditProvider internalAuditProvider = Provider.of(context, listen: false);
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save();
+ _model.attachments=[];
+ for (var item in _attachments) {
+ String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
+ _model.attachments?.add(InternalAuditAttachments(id: item.id, name: fileName));
+ }
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ _model.auditorId = context.userProvider.user?.userID;
+ bool status = await internalAuditProvider.addSystemInternalAudit(context: context, request: _model);
+ Navigator.pop(context);
+ if (status) {
+ Navigator.pop(context);
+ }
+ }
+ }
+
+ Widget _workOrderInfoWidget(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.all(12),
+ decoration: BoxDecoration(
+ color: showLoading ? Colors.white : const Color(0xffF4F6FC),
+ borderRadius: BorderRadius.circular(12),
+ border: Border.all(
+ color: const Color(0xff212936).withOpacity(.03),
+ ),
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ Row(
+ children: [
+ Text(
+ _model.workOrderType?.name ?? 'WO Type',
+ style: TextStyle(
+ fontSize: 14.toScreenWidth,
+ fontWeight: FontWeight.w500,
+ fontStyle: FontStyle.normal,
+ color: Colors.black87,
+ decoration: TextDecoration.none,
+ ),
+ ).expanded,
+ const Icon(
+ Icons.info,
+ color: Color(0xff7D859A),
+ size: 20,
+ ),
+ ],
+ ),
+ 6.height,
+ "${context.translation.site}: ${_model.workOrderDetailModel?.woSite ?? '-'}".bodyText(context),
+ "${'Eng. Name'.addTranslation}: ${_model.workOrderDetailModel?.woAssignedEngineer ?? '-'}".bodyText(context),
+ "${'Asset Name'.addTranslation}: ${_model.workOrderDetailModel?.woAssetName ?? '-'}".bodyText(context),
+ "${context.translation.model}: ${_model.workOrderDetailModel?.woModel ?? '-'}".bodyText(context),
+ "${context.translation.manufacture}: ${_model.workOrderDetailModel?.woManufacturer ?? '-'}".bodyText(context),
+ "${'SN'.addTranslation}: ${_model.workOrderDetailModel?.wosn ?? '-'}".bodyText(context),
+ "${context.translation.assetNo}: ${_model.workOrderDetailModel?.woAssetNo ?? '-'}".bodyText(context),
+ ],
+ ),
+ ).toShimmer(isShow: showLoading, context: context);
+ }
+
+ void updateWorkOrderReference({int? woTypeId, int? selectedId}) {
+ _clearWorkOrderSelectionIds();
+ if (woTypeId == null || selectedId == null) return;
+ switch (woTypeId) {
+ case 1: // CM
+ _model.correctiveMaintenanceId = selectedId;
+ break;
+ case 2: // Gas Refill
+ _model.gasRefillId = selectedId;
+ break;
+ case 3: // Asset Transfer
+ _model.assetTransferId = selectedId;
+ break;
+ case 4: // PPM Request
+ _model.planPreventiveVisitId = selectedId;
+ break;
+ case 5: // Recurrent WOx
+ _model.planRecurrentTaskId = selectedId;
+ break;
+ case 6: // Task
+ _model.taskJobId = selectedId;
+ break;
+ case 7: // Recall & Alert
+ _model.taskAlertJobId = selectedId;
+ break;
+ }
+ }
+
+ void _clearWorkOrderSelectionIds() {
+ _model.correctiveMaintenanceId = null;
+ _model.planPreventiveVisitId = null;
+ _model.assetTransferId = null;
+ _model.taskJobId = null;
+ _model.taskAlertJobId = null;
+ _model.gasRefillId = null;
+ _model.planRecurrentTaskId = null;
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart
new file mode 100644
index 00000000..9aa79453
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_audit_work_order_auto_complete_field.dart
@@ -0,0 +1,149 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/app_style/app_text_style.dart';
+import 'package:test_sa/views/app_style/sizing.dart';
+
+class SystemAuditWoAutoCompleteField extends StatefulWidget {
+ final String initialValue;
+ final int? woTypeId;
+ final TextEditingController controller;
+ final bool clearAfterPick;
+ final Function(WoAutoCompleteModel) onPick;
+
+ const SystemAuditWoAutoCompleteField({Key? key, required this.initialValue, this.woTypeId, required this.onPick, this.clearAfterPick = true, required this.controller}) : super(key: key);
+
+ @override
+ _SystemAuditWoAutoCompleteFieldState createState() => _SystemAuditWoAutoCompleteFieldState();
+}
+
+class _SystemAuditWoAutoCompleteFieldState extends State {
+ late InternalAuditProvider _provider;
+
+ //
+ // late TextEditingController _controller;
+
+ bool loading = false;
+
+ @override
+ void initState() {
+ // w controller = widget.controller ?? TextEditingController(text: widget.initialValue);
+ super.initState();
+ _provider = Provider.of(context, listen: false);
+ }
+
+ @override
+ void didUpdateWidget(covariant SystemAuditWoAutoCompleteField oldWidget) {
+ // if (widget.initialValue != oldWidget.initialValue) {
+ // // _controller = widget.controller ?? TextEditingController(text: widget.initialValue);
+ // }
+ super.didUpdateWidget(oldWidget);
+ }
+
+ @override
+ void dispose() {
+ if (widget.controller == null) {
+ // _controller.dispose();
+ }
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
+ return Container(
+ decoration: BoxDecoration(
+ color: AppColor.background(context),
+ borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
+ // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
+ ),
+ child: Autocomplete(
+ optionsBuilder: (TextEditingValue textEditingValue) async {
+ if (textEditingValue.text.isEmpty) {
+ if (loading) {
+ setState(() {
+ loading = false;
+ });
+ }
+ return const Iterable.empty();
+ }
+ if (!loading) {
+ setState(() {
+ loading = true;
+ });
+ }
+ List workOrders = (await _provider.getWorkOrderByWoType(text: textEditingValue.text, woId:widget.woTypeId));
+ setState(() {
+ loading = false;
+ });
+ return workOrders;
+ },
+ displayStringForOption: (WoAutoCompleteModel option) => option.displayName ?? '',
+ fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
+ return TextField(
+ controller: widget.controller,
+ focusNode: fieldFocusNode,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
+ textAlign: TextAlign.start,
+ decoration: InputDecoration(
+ border: border,
+ disabledBorder: border,
+ focusedBorder: border,
+ enabledBorder: border,
+ errorBorder: border,
+ contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
+ constraints: const BoxConstraints(),
+ suffixIconConstraints: const BoxConstraints(maxHeight: 24, maxWidth: 24 + 8),
+ filled: true,
+ fillColor: AppColor.fieldBgColor(context),
+ errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
+ floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
+ labelText: context.translation.woNumber,
+ labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
+ suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
+ ),
+ textInputAction: TextInputAction.search,
+ onChanged: (text) {
+ fieldTextEditingController.text = text;
+ },
+ onSubmitted: (String value) {
+ onFieldSubmitted();
+ },
+ );
+ },
+ onSelected: (WoAutoCompleteModel selection) {
+ if (widget.clearAfterPick) {
+ widget.controller.clear();
+ } else {
+ widget.controller.text = (selection.displayName ?? "");
+ }
+ widget.onPick(selection);
+ },
+ ),
+ );
+ }
+
+ // String getUrl(int? woTypeId) {
+ // if (woTypeId == null) return '';
+ // String base = URLs.woAutoCompleteBase;
+ // var urlMap = {
+ // 1: '$base/ServiceRequest/WorkOrderAutoComplete', // CM
+ // 2: '$base/GasRefill/GetGasRefillAutoComplete', // Gas Refill
+ // 3: '$base/AssetTransfer/GetAssetTransferAutoComplete', // Asset Transfer
+ // 4: '$base/PlanPreventiveVisit/GetAutoCompletePlanPreventiveVisit', // PPM Request
+ // 5: '$base/PlanRecurrentTasks/GetPlanRecurrentTask', // Recurrent WO
+ // 6: '$base/TaskJobs/AutocompleteTaskJob', // Task
+ // 7: '$base/TaskJobs/AutocompleteTaskJob', // Recall & Alert
+ // };
+ // return urlMap[woTypeId] ?? '';
+ // }
+}
diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart
new file mode 100644
index 00000000..484d5b4e
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart
@@ -0,0 +1,219 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/update_equipment_internal_audit_page.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/views/widgets/images/files_list.dart';
+
+import 'package:test_sa/views/widgets/loaders/app_loading.dart';
+
+class SystemInternalAuditDetailPage extends StatefulWidget {
+ static const String id = "/details-system-internal-audit";
+ final int auditId;
+
+ SystemInternalAuditDetailPage({Key? key, required this.auditId}) : super(key: key);
+
+ @override
+ _SystemInternalAuditDetailPageState createState() {
+ return _SystemInternalAuditDetailPageState();
+ }
+}
+
+class _SystemInternalAuditDetailPageState extends State {
+ bool isWoType = true;
+ SystemInternalAuditDataModel? model;
+ late InternalAuditProvider _internalAuditProvider;
+ List allAttachments = [];
+
+ @override
+ void initState() {
+ super.initState();
+ _internalAuditProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getAuditData();
+ });
+ }
+
+ Future getAuditData() async {
+ model = await _internalAuditProvider.getInternalSystemAuditById(widget.auditId);
+ allAttachments.clear();
+ allAttachments = [
+ ...(model?.attachments ?? []),
+ ...(model?.engineerData?.attachments ?? []),
+ ];
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ //TODO need to check when implementing provider needed or not .
+ return Scaffold(
+ appBar: const DefaultAppBar(title: "Request Details"),
+ body: Selector(
+ selector: (_, provider) => provider.isLoading,
+ builder: (_, isLoading, __) {
+ if (isLoading) return const ALoading();
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ assetInformation(),
+ 8.height,
+ workOrderInformation(),
+ 8.height,
+ //TODO need to check for comments
+ if (model?.findingDescription?.isNotEmpty ?? false) ...[
+ const Divider().defaultStyle(context),
+ // Text(
+ // "Comments".addTranslation,
+ // style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ // ),
+ model!.findingDescription!.bodyText(context),
+ ],
+ //TODO need to check for attachments
+ if (allAttachments.isNotEmpty) ...[
+ const Divider().defaultStyle(context),
+ Text(
+ "Attachments".addTranslation,
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 8.height,
+ FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []),
+ ],
+ ],
+ ).paddingAll(0).toShadowContainer(context),
+ ).expanded,
+ if (context.userProvider.isEngineer)
+ FooterActionButton.footerContainer(
+ context: context,
+ child: AppFilledButton(
+ buttonColor: AppColor.primary10,
+ label: "Update",
+ onPressed: () async {
+ final result = await Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (_) => UpdateSystemInternalAuditPage(model: model),
+ ),
+ );
+ if (result == true) {
+ await getAuditData();
+ setState(() {}); // refresh UI with new model
+ }
+ }),
+ ),
+ ],
+ );
+ },
+ ));
+ }
+
+ Widget workOrderInformation() {
+ final details = model?.workOrderDetails;
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Divider().defaultStyle(context),
+ Text(
+ "WO Info",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ labelValueText(context, context.translation.woNumber, details?.workOrderNo),
+ labelValueText(context, 'WO Type'.addTranslation, model?.workOrderType?.name),
+ labelValueText(context, context.translation.site, details?.woSite),
+ labelValueText(context, context.translation.assetName, details?.woAssetName),
+ labelValueText(context, context.translation.manufacture, details?.woManufacturer),
+ labelValueText(context, context.translation.model, details?.woModel),
+ ],
+ );
+ }
+
+ Widget requestDetails() {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Divider().defaultStyle(context),
+ Text(
+ "Request Details",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ checklistWidget(value: 'Asset Tag'.addTranslation),
+ checklistWidget(value: 'Expired PM Tag'.addTranslation),
+ ],
+ );
+ }
+
+ Widget assetInformation() {
+ final details = model?.workOrderDetails;
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "Asset Details",
+ style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
+ ),
+ 6.height,
+ labelValueText(context, context.translation.assetName, details?.woAssetName),
+ labelValueText(context, context.translation.assetNo, details?.woAssetNo),
+ labelValueText(context, context.translation.manufacture, details?.woManufacturer),
+ labelValueText(context, context.translation.model, details?.woModel),
+ ],
+ );
+ }
+
+ Widget labelValueText(BuildContext context, String label, String? value) {
+ if (value == null || value.isEmpty) return const SizedBox.shrink();
+
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 4),
+ child: Text(
+ '$label: $value',
+ style: AppTextStyles.bodyText.copyWith(
+ color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
+ ),
+ ),
+ );
+ }
+
+ Widget checklistWidget({required String value}) {
+ return Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Checkbox(
+ value: true,
+ activeColor: AppColor.neutral120,
+ materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ visualDensity: const VisualDensity(horizontal: -4, vertical: -3),
+ onChanged: (value) {},
+ ),
+ value.bodyText(context),
+ ],
+ );
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart
new file mode 100644
index 00000000..0d32a4a8
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart
@@ -0,0 +1,117 @@
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/all_requests_and_count_model.dart';
+import 'package:test_sa/models/new_models/dashboard_detail.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_detail_page.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_detail_page.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/widgets/requests/request_status.dart';
+
+class SystemInternalAuditItemView extends StatelessWidget {
+ final Data? requestData;
+ final RequestsDetails? requestDetails;
+ final bool showShadow;
+
+ const SystemInternalAuditItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ //TODO need to refactor this code repetation @waseem
+ if (requestData != null) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StatusLabel(
+ label: requestData!.statusName!,
+ textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
+ backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!),
+ ),
+ 1.width.expanded,
+ Text(
+ requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
+ textAlign: TextAlign.end,
+ style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
+ ),
+ ],
+ ),
+ 8.height,
+ (requestData?.typeTransaction ?? "Internal Audit Request").heading5(context),
+ infoWidget(label: context.translation.assetNo, value: requestData?.assetNumber, context: context),
+
+ 8.height,
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.translation.viewDetails,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
+ ),
+ 4.width,
+ Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
+ ],
+ ),
+ ],
+ ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
+ Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!)));
+ });
+ }
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StatusLabel(
+ label: requestDetails!.status!,
+ textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
+ backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!),
+ ),
+ 1.width.expanded,
+ Text(
+ requestDetails!.date?.toServiceRequestCardFormat ?? "",
+ textAlign: TextAlign.end,
+ style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
+ ),
+ ],
+ ),
+ 8.height,
+ (requestDetails?.nameOfType ?? "Internal Audit Request").heading5(context),
+ infoWidget(label: context.translation.assetNumber, value: requestDetails!.assetNo, context: context),
+ infoWidget(label: context.translation.assetSN, value: requestDetails!.assetSN, context: context),
+ infoWidget(label: context.translation.model, value: requestDetails!.model, context: context),
+ 8.height,
+ // infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
+ 8.height,
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.translation.viewDetails,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
+ ),
+ 4.width,
+ Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
+ ],
+ ),
+ ],
+ ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
+ Navigator.push(context, MaterialPageRoute(builder: (context) => SystemInternalAuditDetailPage(auditId: requestDetails!.id!)));
+ });
+ }
+
+ Widget infoWidget({required String label, String? value, required BuildContext context}) {
+ if (value != null && value.isNotEmpty) {
+ return '$label: $value'.bodyText(context);
+ }
+ return const SizedBox();
+ }
+}
diff --git a/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart b/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart
new file mode 100644
index 00000000..1d50b7b8
--- /dev/null
+++ b/lib/modules/internal_audit_module/pages/system_internal_audit/update_system_internal_audit_page.dart
@@ -0,0 +1,316 @@
+import 'dart:convert';
+import 'dart:developer';
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/models/generic_attachment_model.dart';
+import 'package:test_sa/models/timer_model.dart';
+import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_timer_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
+import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
+import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
+import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
+import 'package:test_sa/views/widgets/timer/app_timer.dart';
+import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
+
+class UpdateSystemInternalAuditPage extends StatefulWidget {
+ static const String id = "update-system-internal-audit";
+ SystemInternalAuditDataModel? model;
+
+ UpdateSystemInternalAuditPage({Key? key, this.model}) : super(key: key);
+
+ @override
+ State createState() => _UpdateSystemInternalAuditPageState();
+}
+
+class _UpdateSystemInternalAuditPageState extends State {
+ final bool _isLoading = false;
+ double totalWorkingHours = 0.0;
+ AuditFormModel formModel = AuditFormModel();
+ final TextEditingController _workingHoursController = TextEditingController();
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ List _attachments = [];
+
+ //TODO need to check if it's needed or not..
+ List timerList = [];
+
+ @override
+ void initState() {
+ populateForm();
+ super.initState();
+ }
+
+ void populateForm() {
+ formModel.requestId = widget.model?.id;
+ formModel.id = widget.model?.id;
+ _attachments = widget.model?.engineerData?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt() ?? 0, name: e.name!)).toList() ?? [];
+
+ calculateWorkingTime();
+ }
+
+ void calculateWorkingTime() {
+ final helperModel = formModel;
+ final timers = helperModel.auditTimers ?? [];
+ totalWorkingHours = timers.fold(0.0, (sum, item) {
+ if (item.startDate == null || item.endDate == null) return sum;
+ try {
+ final start = DateTime.parse(item.startDate!);
+ final end = DateTime.parse(item.endDate!);
+ final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
+ return sum + diffInHours;
+ } catch (_) {
+ return sum;
+ }
+ });
+ timerList = timers.map((e) {
+ return TimerHistoryModel(
+ id: e.id,
+ startTime: e.startDate,
+ endTime: e.endDate,
+ workingHours: e.startDate,
+ );
+ }).toList();
+ }
+
+ _onSubmit(BuildContext context) async {
+ bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
+ InternalAuditProvider provider = Provider.of(context, listen: false);
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+
+ formModel.auditTimers ??= [];
+ if (formModel.auditTimePicker != null) {
+ int durationInSecond = formModel.auditTimePicker!.endAt!.difference(formModel.auditTimePicker!.startAt!).inSeconds;
+ formModel.auditTimers?.add(
+ InternalAuditTimerModel(
+ id: 0,
+ startDate: formModel.auditTimePicker!.startAt!.toIso8601String(), // Handle potential null
+ endDate: formModel.auditTimePicker!.endAt?.toIso8601String(), // Handle potential null
+ totalWorkingHour: ((durationInSecond) / 60 / 60),
+ ),
+ );
+ }
+ formModel.timerModelList?.forEach((timer) {
+ int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
+ formModel.auditTimers?.add(
+ InternalAuditTimerModel(
+ id: 0,
+ startDate: timer.startAt!.toIso8601String(), // Handle potential null
+ endDate: timer.endAt?.toIso8601String(), // Handle potential null
+ totalWorkingHour: ((durationInSecond) / 60 / 60),
+ ),
+ );
+ });
+
+ _formKey.currentState!.save();
+ formModel.attachments = [];
+ for (var item in _attachments) {
+ String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
+ formModel.attachments!.add(
+ InternalAuditAttachments(
+ id: item.id,
+ // originalName: fileName,
+ name: fileName,
+ ),
+ );
+ }
+ log('submit press');
+ log('data ${formModel.toJson()}');
+ final success = await provider.updateSystemInternalAudit(model: formModel);
+ Navigator.pop(context);
+ if (formModel.isComplete == true) {
+ //Navigate to List screen.
+ } else if (formModel.isComplete == false) {
+ if (success) {
+ Navigator.of(context).pop(true);
+ } else {
+ Fluttertoast.showToast(msg: 'Failed to update');
+ }
+ }
+ }
+
+ @override
+ void dispose() {
+ _workingHoursController.dispose();
+ super.dispose();
+ }
+
+ void updateTimer({TimerModel? timer}) {
+ if (timer?.startAt != null && timer?.endAt != null) {
+ final start = timer!.startAt!;
+ final end = timer.endAt!;
+
+ final difference = end.difference(start);
+ final totalHours = difference.inSeconds / 3600.0;
+ formModel.startTime = start;
+ formModel.endTime = end;
+ formModel.totalHours = totalHours;
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: DefaultAppBar(
+ title: 'Update Information'.addTranslation,
+ onWillPopScope: () {
+ formModel.isComplete = false;
+ _onSubmit(context);
+ },
+ ),
+ key: _scaffoldKey,
+ body: Form(
+ key: _formKey,
+ child: LoadingManager(
+ isLoading: _isLoading,
+ isFailedLoading: false,
+ stateCode: 200,
+ onRefresh: () async {},
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ 8.height,
+ AppTextFormField(
+ labelText: 'Debrief'.addTranslation,
+ textInputType: TextInputType.multiline,
+ hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
+ labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
+ alignLabelWithHint: true,
+ initialValue: formModel.debrief,
+ backgroundColor: AppColor.fieldBgColor(context),
+ showShadow: false,
+ onSaved: (value) {
+ formModel.debrief = value;
+ },
+ ),
+ 8.height,
+ _timerWidget(context, totalWorkingHours),
+ 16.height,
+ AttachmentPicker(
+ label: 'Upload Attachment',
+ attachment: _attachments,
+ buttonColor: AppColor.primary10,
+ onlyImages: false,
+ buttonIcon: 'attachment_icon'.toSvgAsset(
+ color: AppColor.primary10,
+ ),
+ ),
+ 8.height,
+ ],
+ ).toShadowContainer(context),
+ ).expanded,
+ FooterActionButton.footerContainer(
+ context: context,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ AppFilledButton(
+ label: context.translation.save,
+ buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60,
+ textColor: context.isDark ? AppColor.white10 : AppColor.black10,
+ onPressed: () {
+ log('button press ');
+ formModel.isComplete = false;
+ _onSubmit(context);
+ }).expanded,
+ 12.width,
+ AppFilledButton(
+ label: context.translation.complete,
+ buttonColor: AppColor.primary10,
+ onPressed: () {
+ formModel.isComplete = true;
+ _onSubmit(context);
+ }).expanded,
+ ],
+ ),
+ ),
+ ],
+ )),
+ ),
+ ).handlePopScope(
+ cxt: context,
+ onSave: () {
+ formModel.isComplete = false;
+ _onSubmit(context);
+ });
+ }
+
+ Widget _timerWidget(BuildContext context, double totalWorkingHours) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ ///this is for multiple timers...
+ // AppTimer(
+ // label: context.translation.timer,
+ // timer: formModel.auditTimerModel,
+ // // enabled: enableTimer,
+ // pickerTimer: formModel.auditTimePicker,
+ // pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''),
+ // onPick: (time) {
+ // formModel.auditTimePicker = time;
+ // },
+ // timerProgress: (isRunning) {},
+ // onChange: (timer) async {
+ // formModel.auditTimerModel = timer;
+ // if (timer.startAt != null && timer.endAt != null) {
+ // formModel.timerModelList = formModel.timerModelList ?? [];
+ // formModel.timerModelList!.add(timer);
+ // }
+ // return true;
+ // },
+ // ),
+ AppTimer(
+ label: context.translation.workingHours,
+ showPicker: false,
+ timer: formModel.auditTimerModel,
+ pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''),
+ pickerTimer: formModel.auditTimePicker,
+ onPick: (time) {
+ updateTimer(timer: time);
+ },
+ width: double.infinity,
+ decoration: BoxDecoration(
+ color: AppColor.fieldBgColor(context),
+ borderRadius: BorderRadius.circular(10),
+ ),
+ timerProgress: (isRunning) {},
+ onChange: (timer) async {
+ updateTimer(timer: timer);
+ log('here onChange ${timer.startAt}');
+
+ return true;
+ },
+ ),
+ if (totalWorkingHours > 0.0) ...[
+ 12.height,
+ WorkingTimeTile(
+ timerList: timerList,
+ totalWorkingTime: totalWorkingHours,
+ ),
+ ],
+ ],
+ );
+ }
+}
diff --git a/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart
new file mode 100644
index 00000000..e4454551
--- /dev/null
+++ b/lib/modules/internal_audit_module/provider/internal_audit_checklist_provider.dart
@@ -0,0 +1,36 @@
+
+import 'dart:convert';
+
+import 'package:http/http.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/providers/loading_list_notifier.dart';
+
+class InternalAuditCheckListProvider extends LoadingListNotifier {
+ @override
+ Future getData({int? id}) async {
+ if (loading ?? false) return -2;
+ loading = true;
+ notifyListeners();
+ Response response;
+ try {
+ response = await ApiManager.instance.get(URLs.getInternalAuditChecklist);
+ } catch (error) {
+ loading = false;
+ stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ // client's request was successfully received
+ List listJson = json.decode(response.body)["data"];
+ items = listJson.map((department) => Lookup.fromJson(department)).toList();
+ }
+ loading = false;
+ notifyListeners();
+ return response.statusCode;
+ }
+}
+
diff --git a/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart
new file mode 100644
index 00000000..9371cb1d
--- /dev/null
+++ b/lib/modules/internal_audit_module/provider/internal_audit_finding_type_provider.dart
@@ -0,0 +1,34 @@
+import 'dart:convert';
+
+import 'package:http/http.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/providers/loading_list_notifier.dart';
+
+class InternalAuditFindingTypeProvider extends LoadingListNotifier {
+ @override
+ Future getData({int? id}) async {
+ if (loading ?? false) return -2;
+ loading = true;
+ notifyListeners();
+ Response response;
+ try {
+ response = await ApiManager.instance.get(URLs.getInternalAuditFindingType);
+ } catch (error) {
+ loading = false;
+ stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ // client's request was successfully received
+ List listJson = json.decode(response.body)["data"];
+ items = listJson.map((department) => Lookup.fromJson(department)).toList();
+ }
+ loading = false;
+ notifyListeners();
+ return response.statusCode;
+ }
+}
diff --git a/lib/modules/internal_audit_module/provider/internal_audit_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart
new file mode 100644
index 00000000..75f0a436
--- /dev/null
+++ b/lib/modules/internal_audit_module/provider/internal_audit_provider.dart
@@ -0,0 +1,211 @@
+import 'dart:convert';
+import 'dart:developer';
+
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:http/http.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/models/device/asset_search.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/update_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_form_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_data_model.dart';
+import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart';
+import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
+
+class InternalAuditProvider extends ChangeNotifier {
+ final pageItemNumber = 10;
+ final searchPageItemNumber = 10;
+ int pageNo = 1;
+
+ void reset() {
+ pageNo = 1;
+ stateCode = null;
+ }
+
+ int? stateCode;
+ bool isDetailLoading = false;
+ bool nextPage = false;
+ bool isNextPageLoading = false;
+ bool isLoading = false;
+
+ Future getEquipmentInternalAuditById(int id) async {
+ try {
+ isLoading = true;
+ notifyListeners();
+ Response response = await ApiManager.instance.get(
+ "${URLs.getInternalAuditEquipmentById}?internalAuditEquipmentId=$id",
+ );
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final decodedBody = jsonDecode(response.body);
+ EquipmentInternalAuditDataModel model = EquipmentInternalAuditDataModel.fromJson(decodedBody["data"]);
+ isLoading = false;
+ notifyListeners();
+ return model;
+ } else {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ } catch (error) {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ }
+
+ Future getInternalSystemAuditById(int id) async {
+ try {
+ isLoading = true;
+ notifyListeners();
+ Response response = await ApiManager.instance.get("${URLs.getInternalAuditSystemById}?AuditSystemId=$id");
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final decodedBody = jsonDecode(response.body);
+ SystemInternalAuditDataModel model = SystemInternalAuditDataModel.fromJson(decodedBody["data"]);
+ isLoading = false;
+ notifyListeners();
+ return model;
+ } else {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ } catch (error) {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ }
+
+ Future loadAllWorkOrderDetailsByID({required int workOrderTypeId, required int workOrderId}) async {
+ try {
+ isLoading = true;
+ notifyListeners();
+ Response response = await ApiManager.instance.get("${URLs.loadAllWorkOrderDetailsByID}?workOrderTypeId=$workOrderTypeId&workOrderId=$workOrderId");
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final decodedBody = jsonDecode(response.body);
+ SystemAuditWorkOrderDetailModel model = SystemAuditWorkOrderDetailModel.fromJson(decodedBody["data"]);
+ isLoading = false;
+ notifyListeners();
+ return model;
+ } else {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ } catch (error) {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ }
+
+ Future updateEquipmentInternalAudit({required AuditFormModel model}) async {
+ isLoading = true;
+ Response response;
+ try {
+ response = await ApiManager.instance.put(URLs.updateAuditEquipmentsEngineer, body: model.toJson());
+ stateCode = response.statusCode;
+ isLoading = false;
+ notifyListeners();
+ if (stateCode == 200) {
+ return true;
+ }
+ return false;
+ } catch (error) {
+ isLoading = false;
+ stateCode = -1;
+ notifyListeners();
+ return false;
+ }
+ }
+
+ Future updateSystemInternalAudit({required AuditFormModel model}) async {
+ isLoading = true;
+ Response response;
+ try {
+ response = await ApiManager.instance.put(URLs.updateAuditSystemEngineer, body: model.toJson());
+ stateCode = response.statusCode;
+ isLoading = false;
+ notifyListeners();
+ log('status code ${stateCode}');
+ if (stateCode == 200) {
+ return true;
+ }
+ return false;
+ } catch (error) {
+ isLoading = false;
+ stateCode = -1;
+ notifyListeners();
+ return false;
+ }
+ }
+
+ Future addEquipmentInternalAudit({
+ required BuildContext context,
+ required EquipmentInternalAuditFormModel request,
+ }) async {
+ bool status = false;
+ Response response;
+ try {
+ response = await ApiManager.instance.post(URLs.addOrUpdateEquipmentInternalAudit, body: request.toJson());
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ status = true;
+ notifyListeners();
+ } else {
+ Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}");
+ status = false;
+ }
+ return status;
+ } catch (error) {
+ print(error);
+ status = false;
+ notifyListeners();
+ return status;
+ }
+ }
+
+ Future addSystemInternalAudit({
+ required BuildContext context,
+ required SystemInternalAuditFormModel request,
+ }) async {
+ bool status = false;
+ Response response;
+ try {
+ response = await ApiManager.instance.post(URLs.addOrUpdateInternalAuditSystem, body: request.toJson());
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ status = true;
+ notifyListeners();
+ } else {
+ Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}");
+ status = false;
+ }
+ return status;
+ } catch (error) {
+ print(error);
+ status = false;
+ notifyListeners();
+ return status;
+ }
+ }
+
+ Future> getWorkOrderByWoType({String? text, required int? woId}) async {
+ late Response response;
+ try {
+ Response response = await ApiManager.instance.get("${URLs.getWoAutoComplete}?workOrderTypeId=$woId&search=$text");
+ // response = await ApiManager.instance.post(url, body: {"search": text});
+ List woOrderList = [];
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ List categoriesListJson = json.decode(response.body)["data"];
+ woOrderList = categoriesListJson.map((wo) => WoAutoCompleteModel.fromJson(wo)).toList();
+ }
+ return woOrderList;
+ } catch (error) {
+ return [];
+ }
+ }
+}
diff --git a/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart
new file mode 100644
index 00000000..7c7b4e5e
--- /dev/null
+++ b/lib/modules/internal_audit_module/provider/internal_audit_wo_type_provider.dart
@@ -0,0 +1,35 @@
+
+import 'dart:convert';
+
+import 'package:http/http.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/providers/loading_list_notifier.dart';
+
+class InternalAuditWoTypeProvider extends LoadingListNotifier {
+ @override
+ Future getData({int? id}) async {
+ if (loading ?? false) return -2;
+ loading = true;
+ notifyListeners();
+ Response response;
+ try {
+ response = await ApiManager.instance.get(URLs.getInternalAuditWoType);
+ } catch (error) {
+ loading = false;
+ stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ List listJson = json.decode(response.body)["data"];
+ items = listJson.map((department) => Lookup.fromJson(department)).toList();
+ }
+ loading = false;
+ notifyListeners();
+ return response.statusCode;
+ }
+}
+
diff --git a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart
index d25049df..40871d70 100644
--- a/lib/modules/tm_module/tasks_wo/update_task_request_view.dart
+++ b/lib/modules/tm_module/tasks_wo/update_task_request_view.dart
@@ -271,7 +271,7 @@ class _UpdateTaskRequestState extends State {
taskModel?.timerModelList?.forEach((timer) {
int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
taskModel.taskJobActivityEngineerTimers?.add(
- TaskJobActivityEngineerTimer(
+ TaskJobActivityEngineerTimer (
id: 0, startDate: timer.startAt!.toIso8601String(), endDate: timer.endAt?.toIso8601String(), totalWorkingHour: ((durationInSecond) / 60 / 60), comment: timer.comments ?? comments),
);
});
diff --git a/lib/modules/traf_module/asset_analytics_model.dart b/lib/modules/traf_module/asset_analytics_model.dart
new file mode 100644
index 00000000..2f265c1b
--- /dev/null
+++ b/lib/modules/traf_module/asset_analytics_model.dart
@@ -0,0 +1,172 @@
+class AssetAnalytics {
+ num? assetId;
+ String? assetNumber;
+ String? assetName;
+ num? lastPrice;
+ String? lastPONo;
+ String? lastPODate;
+ num? sameAssetQuantity;
+ String? slaStatus;
+ String? contractNumber;
+ String? contractStartDate;
+ String? contractEndDate;
+ num? assetAgeInDays;
+ String? assetAgeDescription;
+ num? totalMaintenanceCost;
+ num? sparePartCost;
+ num? laborCost;
+ num? exchangeCost;
+ num? travelCost;
+ num? netBookValue;
+ num? purchasedPrice;
+ num? lifeSpan;
+ num? mtbf;
+ String? mtbfDescription;
+ num? totalCMWorkOrders;
+ num? downTimeHours;
+ String? downTimeDescription;
+ num? upTimeHours;
+ String? upTimeDescription;
+ num? operationHours;
+ String? installationDate;
+ String? modelName;
+ String? manufacturerName;
+ String? serialNumber;
+ String? departmentName;
+ String? siteName;
+ num? id;
+ String? createdBy;
+ String? createdDate;
+ String? modifiedBy;
+ String? modifiedDate;
+
+ AssetAnalytics(
+ {this.assetId,
+ this.assetNumber,
+ this.assetName,
+ this.lastPrice,
+ this.lastPONo,
+ this.lastPODate,
+ this.sameAssetQuantity,
+ this.slaStatus,
+ this.contractNumber,
+ this.contractStartDate,
+ this.contractEndDate,
+ this.assetAgeInDays,
+ this.assetAgeDescription,
+ this.totalMaintenanceCost,
+ this.sparePartCost,
+ this.laborCost,
+ this.exchangeCost,
+ this.travelCost,
+ this.netBookValue,
+ this.purchasedPrice,
+ this.lifeSpan,
+ this.mtbf,
+ this.mtbfDescription,
+ this.totalCMWorkOrders,
+ this.downTimeHours,
+ this.downTimeDescription,
+ this.upTimeHours,
+ this.upTimeDescription,
+ this.operationHours,
+ this.installationDate,
+ this.modelName,
+ this.manufacturerName,
+ this.serialNumber,
+ this.departmentName,
+ this.siteName,
+ this.id,
+ this.createdBy,
+ this.createdDate,
+ this.modifiedBy,
+ this.modifiedDate});
+
+ AssetAnalytics.fromJson(Map json) {
+ assetId = json['assetId'];
+ assetNumber = json['assetNumber'];
+ assetName = json['assetName'];
+ lastPrice = json['lastPrice'];
+ lastPONo = json['lastPONo'];
+ lastPODate = json['lastPODate'];
+ sameAssetQuantity = json['sameAssetQuantity'];
+ slaStatus = json['slaStatus'];
+ contractNumber = json['contractNumber'];
+ contractStartDate = json['contractStartDate'];
+ contractEndDate = json['contractEndDate'];
+ assetAgeInDays = json['assetAgeInDays'];
+ assetAgeDescription = json['assetAgeDescription'];
+ totalMaintenanceCost = json['totalMaintenanceCost'];
+ sparePartCost = json['sparePartCost'];
+ laborCost = json['laborCost'];
+ exchangeCost = json['exchangeCost'];
+ travelCost = json['travelCost'];
+ netBookValue = json['netBookValue'];
+ purchasedPrice = json['purchasedPrice'];
+ lifeSpan = json['lifeSpan'];
+ mtbf = json['mtbf'];
+ mtbfDescription = json['mtbfDescription'];
+ totalCMWorkOrders = json['totalCMWorkOrders'];
+ downTimeHours = json['downTimeHours'];
+ downTimeDescription = json['downTimeDescription'];
+ upTimeHours = json['upTimeHours'];
+ upTimeDescription = json['upTimeDescription'];
+ operationHours = json['operationHours'];
+ installationDate = json['installationDate'];
+ modelName = json['modelName'];
+ manufacturerName = json['manufacturerName'];
+ serialNumber = json['serialNumber'];
+ departmentName = json['departmentName'];
+ siteName = json['siteName'];
+ id = json['id'];
+ createdBy = json['createdBy'];
+ createdDate = json['createdDate'];
+ modifiedBy = json['modifiedBy'];
+ modifiedDate = json['modifiedDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['assetId'] = this.assetId;
+ data['assetNumber'] = this.assetNumber;
+ data['assetName'] = this.assetName;
+ data['lastPrice'] = this.lastPrice;
+ data['lastPONo'] = this.lastPONo;
+ data['lastPODate'] = this.lastPODate;
+ data['sameAssetQuantity'] = this.sameAssetQuantity;
+ data['slaStatus'] = this.slaStatus;
+ data['contractNumber'] = this.contractNumber;
+ data['contractStartDate'] = this.contractStartDate;
+ data['contractEndDate'] = this.contractEndDate;
+ data['assetAgeInDays'] = this.assetAgeInDays;
+ data['assetAgeDescription'] = this.assetAgeDescription;
+ data['totalMaintenanceCost'] = this.totalMaintenanceCost;
+ data['sparePartCost'] = this.sparePartCost;
+ data['laborCost'] = this.laborCost;
+ data['exchangeCost'] = this.exchangeCost;
+ data['travelCost'] = this.travelCost;
+ data['netBookValue'] = this.netBookValue;
+ data['purchasedPrice'] = this.purchasedPrice;
+ data['lifeSpan'] = this.lifeSpan;
+ data['mtbf'] = this.mtbf;
+ data['mtbfDescription'] = this.mtbfDescription;
+ data['totalCMWorkOrders'] = this.totalCMWorkOrders;
+ data['downTimeHours'] = this.downTimeHours;
+ data['downTimeDescription'] = this.downTimeDescription;
+ data['upTimeHours'] = this.upTimeHours;
+ data['upTimeDescription'] = this.upTimeDescription;
+ data['operationHours'] = this.operationHours;
+ data['installationDate'] = this.installationDate;
+ data['modelName'] = this.modelName;
+ data['manufacturerName'] = this.manufacturerName;
+ data['serialNumber'] = this.serialNumber;
+ data['departmentName'] = this.departmentName;
+ data['siteName'] = this.siteName;
+ data['id'] = this.id;
+ data['createdBy'] = this.createdBy;
+ data['createdDate'] = this.createdDate;
+ data['modifiedBy'] = this.modifiedBy;
+ data['modifiedDate'] = this.modifiedDate;
+ return data;
+ }
+}
diff --git a/lib/modules/traf_module/asset_auto_complete_field.dart b/lib/modules/traf_module/asset_auto_complete_field.dart
index 0abb378b..e215c4a7 100644
--- a/lib/modules/traf_module/asset_auto_complete_field.dart
+++ b/lib/modules/traf_module/asset_auto_complete_field.dart
@@ -105,7 +105,7 @@ class _AssetAutoCompleteFieldState extends State {
fillColor: AppColor.fieldBgColor(context),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
- labelText: context.translation.oracleCode,
+ labelText: "Name/Oracle Code",
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
),
diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart
index 69756285..66133805 100644
--- a/lib/modules/traf_module/create_traf_request_page.dart
+++ b/lib/modules/traf_module/create_traf_request_page.dart
@@ -165,6 +165,10 @@ class _CreateTRAFRequestPageState extends State {
AppTextFormField(
initialValue: "",
labelText: "How would the requested technology solve the current situation and/or serve the purpose?",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -178,6 +182,10 @@ class _CreateTRAFRequestPageState extends State {
AppTextFormField(
initialValue: "",
labelText: "What is the current practice?",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -191,6 +199,10 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q1",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -204,6 +216,10 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q2",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -217,6 +233,10 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q3",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -230,6 +250,10 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q4",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -264,7 +288,8 @@ class _CreateTRAFRequestPageState extends State {
dense: true,
contentPadding: EdgeInsets.zero,
title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"),
- subtitle: Text("Email: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
+ subtitle: Text(
+ "Position: ${userBasedOnSearch[index].position ?? "-"}\nEmail: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() {
userBasedOnSearch.removeAt(index);
setState(() {});
@@ -286,7 +311,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: isUsedSolelyOrShared,
onSelect: (value) {
isUsedSolelyOrShared = value;
- trafRequest?.usingSolelyOrSharedId = value?.value;
+ trafRequest?.usingSolelyOrSharedId = value?.id;
if (isUsedSolelyOrShared?.value != 1) {
departments = [];
trafRequest?.trafDepartments = [];
@@ -329,7 +354,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: otherServicesEffects,
onSelect: (value) {
otherServicesEffects = value;
- trafRequest?.isEffectedId = value?.value;
+ trafRequest?.isEffectedId = value?.id;
if (otherServicesEffects?.value != 1) {
trafRequest?.effectedServices = null;
FocusScope.of(context).unfocus();
@@ -347,6 +372,10 @@ class _CreateTRAFRequestPageState extends State {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: otherServicesEffectsNode,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
labelText: "List down these services and stat how would it be effected",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -367,7 +396,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: useInCombination,
onSelect: (value) {
useInCombination = value;
- trafRequest?.isCombinationId = value?.value;
+ trafRequest?.isCombinationId = value?.id;
if (useInCombination?.value != 1) {
trafRequest?.usedWithCombination = null;
FocusScope.of(context).unfocus();
@@ -384,6 +413,10 @@ class _CreateTRAFRequestPageState extends State {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: useInCombinationNode,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
labelText: "kindly describe in detail",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -430,11 +463,46 @@ class _CreateTRAFRequestPageState extends State {
}
void _verifyAndSubmit() async {
+ if (requestType == null) {
+ "Select request type".showToast;
+ return;
+ } else if (requestType?.value == 1 && trafRequest?.assetNDId == null) {
+ "Oracle Code missing".showToast;
+ return;
+ } else if (requestType?.value == 2 && trafRequest?.assetId == null) {
+ "Pick asset".showToast;
+ return;
+ }
+ if (!_formKey.currentState!.validate()) return;
+
trafRequest?.employeeId = context.userProvider.user?.userID;
trafRequest?.siteId = context.userProvider.user?.clientId;
trafRequest?.trafContacts = [];
trafRequest?.trafContacts = userBasedOnSearch.map((item) => TrafContacts(id: 0, trafId: 0, name: item.userName, userId: item.userId)).toList();
+ if ((trafRequest?.trafContacts ?? []).isEmpty) {
+ "Please specify users going to use technology".showToast;
+ return;
+ }
+ if (isUsedSolelyOrShared == null) {
+ "Please specify technology solely or shared".showToast;
+ return;
+ }
+ if (isUsedSolelyOrShared?.value == 1 && (trafRequest?.trafDepartments ?? []).isEmpty) {
+ "Please specify departments and relations".showToast;
+ return;
+ }
+
+ if (otherServicesEffects == null) {
+ "Please specify other services will be effected or not".showToast;
+ return;
+ }
+
+ if (useInCombination == null) {
+ "Please specify equipment used in combination or not".showToast;
+ return;
+ }
+
Utils.showLoading(context);
bool isSuccess = await Provider.of(context, listen: false).addTraf(trafRequest!.toJson());
Utils.hideLoading(context);
diff --git a/lib/modules/traf_module/traf_request_detail_page.dart b/lib/modules/traf_module/traf_request_detail_page.dart
index c69073c7..00f25512 100644
--- a/lib/modules/traf_module/traf_request_detail_page.dart
+++ b/lib/modules/traf_module/traf_request_detail_page.dart
@@ -15,6 +15,7 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+import 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestDetailPage extends StatefulWidget {
@@ -93,14 +94,14 @@ class _TrafRequestDetailPageState extends State {
),
8.height,
'${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context),
- '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), // todo ask shaheer
- '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), // todo ask shaheer
- 'Position: ${data.positionName ?? '-'}'.bodyText(context), // todo ask shaheer
+ '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context),
+ '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context),
+ 'Position: ${data.positionName ?? '-'}'.bodyText(context),
'${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context),
- '${context.translation.department}: ${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
- 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
- '${context.translation.extensionNo}: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
- '${context.translation.phoneNumber}: ${data.requesterContactNumber ?? '-'}'.bodyText(context),
+ '${context.translation.department}: ${data.departmentName}'.bodyText(context),
+ // 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
+ 'Number/Contact Information: ${data.requesterContactNumber ?? '-'}'.bodyText(context),
+ 'Extension: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@@ -131,10 +132,22 @@ class _TrafRequestDetailPageState extends State {
.bodyText(context),
4.height,
'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context),
+ if ((data.departments ?? []).isNotEmpty) ...[
+ 4.height,
+ 'Technology used with other departments:\n${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
+ ],
4.height,
- 'Would other services be effected by acquiring the new equipment?:\n${data.effectedServices ?? '-'}'.bodyText(context),
+ 'Would other services be effected by acquiring the new equipment?:\n${data.isEffectedName ?? '-'}'.bodyText(context),
+ if ((data.effectedServices ?? "").isNotEmpty) ...[
+ 4.height,
+ 'List of services would it be effected:\n${data.effectedServices ?? '-'}'.bodyText(context),
+ ],
4.height,
- 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
+ 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.isCombinationName ?? '-'}'.bodyText(context),
+ if ((data.usedWithCombination ?? "").isNotEmpty) ...[
+ 4.height,
+ 'Equipment going to be used with combination of other equipments:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
+ ],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@@ -153,16 +166,29 @@ class _TrafRequestDetailPageState extends State {
'${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context),
'${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context),
if (data.requestTypeId == 733) ...[
- 'Last price & PO: ${data.poNumber ?? '-'}'.bodyText(context),
- 'The quantity of the same asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Existing asset under SLA: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Age of the asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Total Maintenance Cost (TMC): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Net Book Value (NBV): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Mean Time Between Failure (MTBF): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Down Time (DT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Up Time (UT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Purchased Price: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
+ FutureBuilder(
+ future: Provider.of(context, listen: false).getAssetAnalytics(data.assetId!),
+ builder: (cxt, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return const SizedBox.square(dimension: 24, child: CircularProgressIndicator()).center;
+ }
+ if (snapshot.hasData) {
+ return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+ 'Last price: ${snapshot.data?.lastPrice ?? '-'}'.bodyText(context),
+ 'PO: ${snapshot.data?.lastPONo ?? '-'}'.bodyText(context),
+ 'The quantity of the same asset: ${snapshot.data?.sameAssetQuantity ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Existing asset under SLA: ${snapshot.data?.slaStatus ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Age of the asset: ${snapshot.data?.assetAgeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Total Maintenance Cost (TMC): ${snapshot.data?.totalMaintenanceCost ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Net Book Value (NBV): ${snapshot.data?.netBookValue ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Mean Time Between Failure (MTBF): ${snapshot.data?.mtbfDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Down Time (DT): ${snapshot.data?.downTimeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Up Time (UT): ${snapshot.data?.upTimeDescription ?? '-'}'.bodyText(context),
+ 'Purchased Price: ${snapshot.data?.purchasedPrice ?? '-'}'.bodyText(context),
+ ]);
+ }
+ return const SizedBox();
+ })
],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
diff --git a/lib/modules/traf_module/traf_request_model.dart b/lib/modules/traf_module/traf_request_model.dart
index 9234ba60..af3977be 100644
--- a/lib/modules/traf_module/traf_request_model.dart
+++ b/lib/modules/traf_module/traf_request_model.dart
@@ -51,6 +51,8 @@ class TrafRequestDataModel {
String? employeeEmail;
int? positionId;
String? positionName;
+ String? departmentId;
+ String? departmentName;
List? departments;
List? trafDepartments;
int? siteId;
@@ -147,6 +149,8 @@ class TrafRequestDataModel {
this.employeeEmail,
this.positionId,
this.positionName,
+ this.departmentId,
+ this.departmentName,
this.departments,
this.trafDepartments,
this.siteId,
@@ -243,6 +247,8 @@ class TrafRequestDataModel {
employeeEmail = json['employeeEmail'];
positionId = json['positionId'];
positionName = json['positionName'];
+ departmentId = json['departmentId'];
+ departmentName = json['departmentName'];
if (json['departments'] != null) {
departments = [];
json['departments'].forEach((v) {
@@ -366,6 +372,8 @@ class TrafRequestDataModel {
data['employeeEmail'] = this.employeeEmail;
data['positionId'] = this.positionId;
data['positionName'] = this.positionName;
+ data['departmentId'] = this.departmentId;
+ data['departmentName'] = this.departmentName;
if (this.departments != null) {
data['departments'] = this.departments!.map((v) => v.toJson()).toList();
}
diff --git a/lib/modules/traf_module/traf_request_provider.dart b/lib/modules/traf_module/traf_request_provider.dart
index 3626eab0..346f7351 100644
--- a/lib/modules/traf_module/traf_request_provider.dart
+++ b/lib/modules/traf_module/traf_request_provider.dart
@@ -5,6 +5,7 @@ import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestProvider extends ChangeNotifier {
@@ -43,4 +44,16 @@ class TrafRequestProvider extends ChangeNotifier {
return -1;
}
}
+
+ Future getAssetAnalytics(int assetId) async {
+ try {
+ Response response = await ApiManager.instance.get("${URLs.getAssetAnalytics}?assetId=$assetId");
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ return AssetAnalytics.fromJson(json.decode(response.body)["data"]);
+ }
+ } catch (error) {
+ print(error);
+ }
+ return null;
+ }
}
diff --git a/lib/modules/traf_module/users_auto_complete_field.dart b/lib/modules/traf_module/users_auto_complete_field.dart
index 12060844..c5d04db7 100644
--- a/lib/modules/traf_module/users_auto_complete_field.dart
+++ b/lib/modules/traf_module/users_auto_complete_field.dart
@@ -81,13 +81,13 @@ class _UsersAutoCompleteFieldState extends State {
loading = true;
});
}
- List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text));
+ List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(context.userProvider.user!.clientId!, textEditingValue.text));
setState(() {
loading = false;
});
return workOrders;
},
- displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? option.userName ?? "" : option.employeeId ?? "",
+ displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (Nurse)" ?? "" : option.employeeId ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
diff --git a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
index d0df92fa..9adf0b97 100644
--- a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
+++ b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
@@ -210,7 +210,7 @@ class _MultipleItemDropDownMenuState requestsList(BuildContext context) {
List list = [];
-
- if (context.userProvider.isAssessor) {
+ log('user type is ${context.userProvider.isQualityUser}');
+ if (context.userProvider.isQualityUser) {
+ list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id));
+ list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id));
+ } else if (context.userProvider.isAssessor) {
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
} else if (context.userProvider.isEngineer) {
if (Provider.of(context, listen: false).engineerCanCreateCM) {
diff --git a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart
index 9cfce9d4..7305a81a 100644
--- a/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart
+++ b/lib/new_views/pages/land_page/my_request/all_requests_filter_page.dart
@@ -71,6 +71,8 @@ class _AllRequestsFilterPageState extends State {
if (isEngineer) {
types[context.translation.recurrentWo] = 5;
+ types["Equipment Internal Audit".addTranslation] = 10;
+ types["System Internal Audit".addTranslation] = 11;
}
if (context.settingProvider.isUserFlowMedical && isEngineer) {
@@ -80,9 +82,13 @@ class _AllRequestsFilterPageState extends State {
if (!isEngineer) {
types['TRAF'] = 9;
}
+
if (context.userProvider.isAssessor) {
types = {"TRAF": 9};
}
+ if (context.userProvider.isQualityUser) {
+ types = {'Equipment Internal Audit': 10, 'System Internal Audit': 11};
+ }
final statuses = {
"All WO": 0,
diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart
index f24d1719..641c0243 100644
--- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart
+++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart
@@ -1,5 +1,7 @@
//request main page
+import 'dart:developer';
+
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
@@ -42,9 +44,11 @@ class _MyRequestsPageState extends State {
Request(2, context.translation.gasRefill),
Request(3, context.translation.transferAsset),
Request(4, context.translation.preventiveMaintenance),
+
];
if (Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(5, context.translation.recurrentWo));
+
}
//TODO unCommit this to enable task
requestsList.add(Request(6, context.translation.taskRequest));
@@ -58,6 +62,11 @@ class _MyRequestsPageState extends State {
if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF'));
}
+ if (context.userProvider.isEngineer) {
+ // TODO need to replace with actual number.
+ requestsList.add(Request(10, 'Equipment Internal Audit'));
+ requestsList.add(Request(11, 'System Internal Audit'));
+ }
if (context.userProvider.isAssessor) {
requestsList = [
@@ -65,6 +74,14 @@ class _MyRequestsPageState extends State {
Request(9, 'TRAF'),
];
}
+ if (context.userProvider.isQualityUser) {
+ requestsList = [
+ Request(null, context.translation.allWorkOrder),
+ //TODO need to replace with actual number.
+ Request(10, 'Equipment Internal Audit'),
+ Request(11, 'System Internal Audit'),
+ ];
+ }
_provider = Provider.of(context, listen: false);
_provider!.reset();
diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
index e436e87d..750abfd7 100644
--- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
+++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
@@ -66,6 +68,10 @@ class RequestPaginatedListview extends StatelessWidget {
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
+ case 10:
+ return EquipmentInternalAuditItemView(requestData: request);
+ case 11:
+ return SystemInternalAuditItemView(requestData: request);
default:
return Container(
height: 100,
diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
index b84406cc..b8d1f6eb 100644
--- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
+++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
@@ -1,12 +1,17 @@
//request tab page
+import 'dart:developer';
+
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
+import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart';
@@ -29,9 +34,19 @@ class RequestItemViewList extends StatelessWidget {
shrinkWrap: true,
itemBuilder: (cxt, index) {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
+ // if (list[index].transactionType == null) {
+ // return EquipmentInternalAuditItemView(requestDetails: list[index]);
+ // // return Container(
+ // // height: 100,
+ // // width: double.infinity,
+ // // color: AppColor.neutral40,
+ // // );
+ // }
switch (list[index].transactionType) {
case 1:
return ServiceRequestItemView(requestDetails: list[index]);
+ // case 1:
+ // return InternalAuditItemView(requestDetails: list[index]);
case 2:
return GasRefillItemView(requestDetails: list[index]);
case 3:
@@ -48,6 +63,11 @@ class RequestItemViewList extends StatelessWidget {
return InventorySessionItemView(requestDetails: list[index]);
case 9:
return TrafRequestItemView(requestDetails: list[index]);
+ //Need to verify the type No..
+ case 10:
+ return EquipmentInternalAuditItemView(requestDetails: list[index]);
+ case 11:
+ return SystemInternalAuditItemView(requestDetails: list[index]);
default:
Container(
height: 100,
diff --git a/lib/views/widgets/timer/app_timer.dart b/lib/views/widgets/timer/app_timer.dart
index 84179d92..629ad60c 100644
--- a/lib/views/widgets/timer/app_timer.dart
+++ b/lib/views/widgets/timer/app_timer.dart
@@ -22,6 +22,7 @@ class AppTimer extends StatefulWidget {
final TextStyle? style;
final BoxDecoration? decoration;
final bool enabled;
+ final bool showPicker;
final String? label;
final double? width;
@@ -40,6 +41,7 @@ class AppTimer extends StatefulWidget {
this.onPick,
this.timerProgress,
this.enabled = true,
+ this.showPicker = true,
}) : super(key: key);
@override
@@ -126,7 +128,8 @@ class _AppTimerState extends State {
@override
void initState() {
- canPickTime = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
+ ///this is temp check for internal audit
+ canPickTime = widget.showPicker == false ? false : ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
_startAt = widget.timer?.startAt;
_endAt = widget.timer?.endAt;
_running = _startAt != null && _endAt == null;
diff --git a/pubspec.lock b/pubspec.lock
index 1693c075..44813421 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1634,6 +1634,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
+ tree_view_flutter:
+ dependency: "direct main"
+ description:
+ name: tree_view_flutter
+ sha256: "3365e29b7d1b1e6c5098a2a0e77a208a12a9345dfa73865cb4c87657cf387801"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.2"
tuple:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 424aecc3..a7689979 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -95,8 +95,8 @@ dependencies:
safe_device: ^1.2.1
toggle_switch: ^2.3.0
clipboard: ^2.0.2
+ tree_view_flutter: ^1.0.2
audio_waveforms: ^1.3.0
-
signalr_netcore: ^1.4.4
local_auth_darwin: any