Compare commits

...

4 Commits

@ -4,14 +4,14 @@ class URLs {
static const String appReleaseBuildNumber = "31";
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url
// static String _baseUrl = "$_host/mobile";
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module
// static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
@ -68,9 +68,11 @@ class URLs {
//service request new flow urls.
static get nurseDashboardCountUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseCount';
static get qaAuditorCount => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorCount';
static get commissioningEngineerCount => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerCount';
static get nurseDashboardDetailsUrl => '$_baseUrl/ServiceRequest/GetDashboardNurseDetails';
static get qaAuditorDetails => '$_baseUrl/ServiceRequest/GetDashboardQAAuditorDetails';
static get commissioningEngineerDetails => '$_baseUrl/ServiceRequest/GetDashboardCommissioningEngineerDetails';
static get nurseRejectUrl => '$_baseUrl/ServiceRequest/NurseReject';
@ -413,8 +415,10 @@ class URLs {
static get getLineFromExternalPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetLineFromExternalPo';
static get getCostCenterListToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToLineDeliveryInspection';
static get getCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterAndSerialNoToLineDeliveryInspection';
static get getCostCenterToPo => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/GetCostCenterToPo';
static get saveCostCenterToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterToLineDeliveryInspection';
static get saveCostCenterAndSerialNoToLineDeliveryInspection => '$_baseUrl/AssetDeliveryExternalDeliveryInspection/SaveCostCenterAndSerialNoToLineDeliveryInspection';
static get getDeliveryHistories => '$_baseUrl/AssetDeliveryExternalDelivery/GetDeliveryHistories';
//Technical Inscption...
static get getLineFromTechnicalInspection => '$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetLineFromDeliveryInspection';
@ -425,7 +429,7 @@ class URLs {
static get getAssetFromInternalTechnicalInspection => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetFromInternal";
static get getAssetDetailsByAssetId => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/GetAssetByIdFromInternal";
static get saveTechnicalInspectionAsset => "$_baseUrl/AssetDeliveryExternalTechnicalInspection/SaveTechnicalInspectionItem";
static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachments";
static get getAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/GetAttachmentsBasedOnType";
static get saveAttachments => "$_baseUrl/AssetDeliveryExternalDeliveryAttachment/Save";
//End user Acceptance...
static get getEndUserAcceptanceCostCenter => "$_baseUrl/AssetDeliveryEndUserAcceptance/GetEndUserAcceptanceCostCenter";
@ -433,5 +437,6 @@ class URLs {
static get saveEndUserFormData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveMaster";
static get saveEndUserAssetData => "$_baseUrl/AssetDeliveryEndUserAcceptance/SaveDetail";
static get endUserStatusLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=534";
static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5007";
static get endUserRejectionReasonLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=415";
static get attachmentTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=5009";
}

@ -166,7 +166,11 @@ class AllRequestsProvider extends ChangeNotifier {
if (context.userProvider.isNurse) {
list.add(9); //
}
list.add(12); // loan module
list.add(12);
if (context.userProvider.isCommissioningEngineer) {
list = [13];
}
// loan module
return list;
}

@ -47,6 +47,7 @@ class UserProvider extends ChangeNotifier {
bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl;
bool get isQualityUser => user!.type == UsersTypes.qualityUser;
bool get isCommissioningEngineer => user!.type == UsersTypes.commissioningEngineer;
VerifyOtpModel _verifyOtpModel = VerifyOtpModel();
SwipeTransaction _swipeTransactionModel = SwipeTransaction();

@ -106,13 +106,22 @@ class DashBoardProvider extends ChangeNotifier {
isAllCountLoading = true;
notifyListeners();
String url = '';
if (usersType == UsersTypes.qualityUser) {
url = URLs.qaAuditorCount;
} else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
url = URLs.engineerDashboardCountUrl;
} else {
url = URLs.nurseDashboardCountUrl;
}
// if (usersType == UsersTypes.qualityUser) {
// url = URLs.qaAuditorCount;
// } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
// url = URLs.engineerDashboardCountUrl;
// } else {
// url = URLs.nurseDashboardCountUrl;
// }
final urlMap = {
UsersTypes.qualityUser: URLs.qaAuditorCount,
UsersTypes.commissioningEngineer: URLs.commissioningEngineerCount,
UsersTypes.engineer: URLs.engineerDashboardCountUrl,
UsersTypes.assessor: URLs.engineerDashboardCountUrl,
UsersTypes.assessorTl: URLs.engineerDashboardCountUrl,
};
url = urlMap[usersType] ?? URLs.nurseDashboardCountUrl;
Response response;
try {
response = await ApiManager.instance.post(url, body: {});
@ -235,6 +244,32 @@ class DashBoardProvider extends ChangeNotifier {
}
}
String getDashboardUrl({
required UsersTypes usersType,
int? status,
int? tabId,
}) {
switch (usersType) {
case UsersTypes.qualityUser:
return URLs.qaAuditorDetails;
case UsersTypes.commissioningEngineer:
return URLs.commissioningEngineerDetails;
case UsersTypes.engineer:
case UsersTypes.assessor:
case UsersTypes.assessorTl:
if (status == 0) {
return URLs.engineerDashboardUpcoming;
} else if (status == 1 && tabId == 1) {
return URLs.engineerDashboardNotAssignDetails;
} else {
// status == 1 && tabId == 2 OR any other case
return URLs.engineerDashboardDetailsUrl;
}
default:
return URLs.nurseDashboardDetailsUrl;
}
}
Future<int> getRequestDetail({bool showLoader = true, required UsersTypes usersType, int? status, bool isHighPriority = false, bool isOverdue = false, String? date, int? tabId}) async {
if (showLoader) {
isDetailLoading = showLoader;
@ -243,25 +278,26 @@ class DashBoardProvider extends ChangeNotifier {
Response response;
String url = '';
// if (usersType == UsersTypes.qualityUser) {
// url = URLs.qaAuditorDetails;
// } else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
// //need to check pagination for not assigned task @waseem.
//
// //these checks are to call different apis for dashboard for engineer...
// if (status == 0) {
// url = URLs.engineerDashboardUpcoming;
// } else if (status == 1 && tabId == 1) {
// url = URLs.engineerDashboardNotAssignDetails;
// } else if (status == 1 && tabId == 2) {
// url = URLs.engineerDashboardDetailsUrl;
// } else {
// url = URLs.engineerDashboardDetailsUrl;
// }
// } else {
// url = URLs.nurseDashboardDetailsUrl;
// }
url = getDashboardUrl(usersType: usersType, status: status, tabId: tabId);
if (usersType == UsersTypes.qualityUser) {
url = URLs.qaAuditorDetails;
} else if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
//need to check pagination for not assigned task @waseem.
//these checks are to call different apis for dashboard for engineer...
if (status == 0) {
url = URLs.engineerDashboardUpcoming;
} else if (status == 1 && tabId == 1) {
url = URLs.engineerDashboardNotAssignDetails;
} else if (status == 1 && tabId == 2) {
url = URLs.engineerDashboardDetailsUrl;
} else {
url = URLs.engineerDashboardDetailsUrl;
}
} else {
url = URLs.nurseDashboardDetailsUrl;
}
try {
Map<String, dynamic> body = {"pageNumber": pageNum, "pageSize": pageItemNumber};
@ -383,6 +419,12 @@ class CategoryTabs {
tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4));
return tabs;
}
if (userType == UsersTypes.commissioningEngineer) {
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));
tabs.add(CategoryTabs(label: 'Closed', tag: 3, id: 4));
return tabs;
}
tabs.add(CategoryTabs(label: 'Open', tag: 1, id: 2));
tabs.add(CategoryTabs(label: 'In Progress', tag: 2, id: 3));

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart';
@ -62,6 +63,8 @@ class RequestCategoryList extends StatelessWidget {
return EquipmentInternalAuditItemView(requestData: request);
case 11:
return EquipmentInternalAuditItemView(requestData: request);
case 13:
return AssetDeliveryItemView(requestData: request);
default:
return Container(
height: 100,

@ -125,3 +125,9 @@ enum DropDownMatchType {
identifier,
name,
}
enum CostCenterType {
costCenter,
serialNumber,
}

@ -28,6 +28,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart';
@ -326,6 +327,7 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => PowerSupplyTypeProvider()),
ChangeNotifierProvider(create: (_) => EndUserStatusLookupProvider()),
ChangeNotifierProvider(create: (_) => EndUserRejectionReasonLookupProvider()),
ChangeNotifierProvider(create: (_) => AttachmentTypeLookupProvider()),
],
child: GestureDetector(
onTap: () {

@ -4,5 +4,6 @@ enum UsersTypes {
nurse, // 1
assessor,
assessorTl,
qualityUser
qualityUser,
commissioningEngineer
}

@ -108,10 +108,13 @@ class User {
return UsersTypes.assessor;
case "R-19": // Head Nurse Role
return UsersTypes.assessorTl;
//TODO need to confirm why repeat.
case "R-3": // Quality User
return UsersTypes.qualityUser;
case "R-58": // Quality User
return UsersTypes.qualityUser;
case "R-201": // Quality User
return UsersTypes.commissioningEngineer;
default:
return null;
}

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
class HelperFunction {
static void attachmentTap({required BuildContext context, required AssetDeliveryProvider assetDeliveryProvider, required dynamic deliveryTableItemId}) async {
Lookup? result;
result = await showAttachmentTypeBottomSheet(context);
List<GenericAttachmentModel> list = [];
if (result != null) {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const AppLazyLoading(),
);
list = await assetDeliveryProvider.getAttachments(tableItemId: deliveryTableItemId, attachmentType: result.value);
Navigator.pop(context);
// if (list.isNotEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: deliveryTableItemId,
attachmentType: result!.value,
attachmentList: list,
)));
// }
}
}
static Future<Lookup?> showAttachmentTypeBottomSheet(BuildContext context) {
return showModalBottomSheet<Lookup?>(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (_) {
return SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.only(
top: 16,
left: 16,
right: 16,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SingleItemDropDownMenu<Lookup, AttachmentTypeLookupProvider>(
context: context,
title: context.translation.reason,
onSelect: (value) {
Navigator.pop(context, value);
},
),
],
),
),
);
},
);
}
}

@ -241,7 +241,7 @@ class AssetDeliveryInternalDetail {
num? qtyCancelled;
num? unitPrice;
num? unitPriceWithTax;
String? itemCategory;
Lookup? itemCategory;
num? totalAssets;
num? childPerAsset;
@ -259,7 +259,9 @@ class AssetDeliveryInternalDetail {
qtyCancelled = json['qtyCancelled'];
unitPrice = json['unitPrice'];
unitPriceWithTax = json['unitPriceWithTax'];
itemCategory = json['itemCategory'];
itemCategory = json['itemCategory'] != null
? Lookup.fromJson(json['itemCategory'])
: null;
totalAssets = json['totalAssets'];
childPerAsset = json['childPerAsset'];
}

@ -40,11 +40,6 @@ class CostCenterModel {
data['id'] = id ?? 0;
data['qty'] = quantity;
// data['costCenter'] = costCenter;
// data['acceptedBy'] = acceptedBy;
// data['acceptanceDate'] = acceptanceDate;
// data['acceptedByEmail'] = acceptedByEmail;
// data['acceptedBySignature'] = acceptedBySignature;
data['costCenter'] = costCenterName;
return data;
}

@ -0,0 +1,53 @@
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
class CostCenterSerialNoFormModel {
List<CostCenterModel>? costCenters;
List<SerialNoModel>? serialNos;
CostCenterSerialNoFormModel({
this.costCenters,
this.serialNos,
});
// From JSON
CostCenterSerialNoFormModel.fromJson(Map<String, dynamic> json) {
if (json['costCenters'] != null) {
costCenters = List<CostCenterModel>.from((json['costCenters'] as List).map((e) => CostCenterModel.fromJson(e)));
}
if (json['serialNos'] != null) {
serialNos = List<SerialNoModel>.from((json['serialNos'] as List).map((e) => SerialNoModel.fromJson(e)));
}
}
// To JSON
Map<String, dynamic> toJson() {
return {
'costCenters': costCenters?.map((e) => e.toJson()).toList() ?? [],
'serialNos': serialNos?.map((e) => e.toJson()).toList() ?? [],
};
}
}
class SerialNoModel {
int? id;
String? serialNo;
SerialNoModel({
this.id,
this.serialNo,
});
SerialNoModel.fromJson(Map<String, dynamic> json) {
id = json['id'] ?? json['costCenterId'];
serialNo = json['serialNo'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = {};
data['id'] = id ?? 0;
data['serialNo'] = serialNo;
return data;
}
}

@ -1,6 +1,11 @@
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
class DeliveryInspectionFormModel {
int? assetDeliveryExternalDeliveryId;
String? deliveryInspectionInspectedBy;
InspectionPersonModel? inspectedByModel;
InspectionPersonModel? approvedByModel;
InspectionPersonModel? thirdApprovalModel;
DateTime? deliveryInspectionInspectedDateFrom;
DateTime? deliveryInspectionInspectedDateTo;
num? totalTime;
@ -9,6 +14,9 @@ class DeliveryInspectionFormModel {
DeliveryInspectionFormModel({
this.assetDeliveryExternalDeliveryId,
this.deliveryInspectionInspectedBy,
this.inspectedByModel,
this.approvedByModel,
this.thirdApprovalModel,
this.deliveryInspectionInspectedDateFrom,
this.deliveryInspectionInspectedDateTo,
this.totalTime,
@ -18,20 +26,32 @@ class DeliveryInspectionFormModel {
DeliveryInspectionFormModel.fromJson(Map<String, dynamic> json) {
assetDeliveryExternalDeliveryId = json['assetDeliveryExternalDeliveryId'];
deliveryInspectionInspectedBy = json['deliveryInspectionInspectedBy'];
deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']):null;
deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo']!=null?DateTime.tryParse(json['deliveryInspectionInspectedDateTo']):null;
inspectedByModel = InspectionPersonModel(name: json['deliveryInspectionInspectedBy'], email: json['deliveryInspectionInspectedByEmail'], signature: json['deliveryInspectionInspectedBySignature']);
approvedByModel = InspectionPersonModel(name: json['deliveryInspectionApprovedBy'], email: json['deliveryInspectionApprovedByEmail'], signature: json['deliveryInspectionApprovedBySignature']);
thirdApprovalModel =
InspectionPersonModel(name: json['deliveryInspectionThirdApproverBy'], email: json['deliveryInspectionThirdApproverByEmail'], signature: json['deliveryInspectionThirdApproverBySignature']);
deliveryInspectionInspectedDateFrom = json['deliveryInspectionInspectedDateFrom'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateFrom']) : null;
deliveryInspectionInspectedDateTo = json['deliveryInspectionInspectedDateTo'] != null ? DateTime.tryParse(json['deliveryInspectionInspectedDateTo']) : null;
totalTime = json['totalTime'];
deliveryInspectionApprovedBy = json['deliveryInspectionApprovedBy'];
}
//TODO need to set payload..
Map<String, dynamic> toJson() {
return {
'assetDeliveryExternalDeliveryId': assetDeliveryExternalDeliveryId,
'deliveryInspectionInspectedBy': deliveryInspectionInspectedBy,
'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(),
'deliveryInspectionInspectedDateFrom': deliveryInspectionInspectedDateFrom?.toIso8601String(),
'deliveryInspectionInspectedDateTo': deliveryInspectionInspectedDateTo?.toIso8601String(),
'totalTime': totalTime,
'deliveryInspectionApprovedBy': deliveryInspectionApprovedBy,
'deliveryInspectionInspectedBy': inspectedByModel?.name,
"deliveryInspectionInspectedBySignature": inspectedByModel?.signature,
"deliveryInspectionInspectedByEmail": inspectedByModel?.email,
'deliveryInspectionApprovedBy': approvedByModel?.name,
"deliveryInspectionApprovedBySignature": approvedByModel?.signature,
"deliveryInspectionApprovedByEmail": approvedByModel?.email,
"deliveryInspectionThirdApproverBy": thirdApprovalModel?.name,
"deliveryInspectionThirdApproverBySignature": thirdApprovalModel?.signature,
"deliveryInspectionThirdApproverByEmail": thirdApprovalModel?.email,
};
}
}

@ -0,0 +1,15 @@
import 'package:flutter/services.dart';
class InspectionPersonModel {
String? name;
String? email;
String? signature;
Uint8List? localSignature;
InspectionPersonModel({
this.name,
this.email,
this.signature,
this.localSignature,
});
}

@ -136,7 +136,7 @@ class TechnicalInspectionAssetModel {
Map<String, dynamic> toChildJson() {
final Map<String, dynamic> data = {};
data['id'] = id;
data['id'] = id ?? 0;
data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId;
data['assetNumber'] = assetNumber;
data['assetOriginId'] = assetOrigin?.id;

@ -1,8 +1,10 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
@ -15,21 +17,20 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
class AssetDeliveryAttachmentView extends StatefulWidget {
///Need to check which parm need here.
final int? lineId;
final int? tableItemId;
final int? requestId;
final bool? isHmg;
final int? attachmentType;
final List<GenericAttachmentModel> attachmentList;
const AssetDeliveryAttachmentView({
super.key,
this.lineId,
this.requestId,
required this.attachmentList,
this.attachmentType,
this.tableItemId,
this.isHmg,
});
@override
@ -52,15 +53,17 @@ class _AssetDeliveryAttachmentViewState extends State<AssetDeliveryAttachmentVie
void getInitialData() async {
///get previoues Attachment from Apis.
isLoading = true;
// isLoading = true;
setState(() {});
_attachments = await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId);
isLoading = false;
_attachments = widget.attachmentList;
// await assetDeliveryProvider.getAttachments(tableItemId: widget.tableItemId, attachmentType: widget.attachmentType);
// isLoading = false;
setState(() {});
}
@override
Widget build(BuildContext context) {
log('value ${widget.attachmentType}');
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar(
@ -69,59 +72,79 @@ class _AssetDeliveryAttachmentViewState extends State<AssetDeliveryAttachmentVie
Navigator.pop(context);
},
),
body: isLoading
? const CircularProgressIndicator(color: AppColor.primary10).center
body: widget.attachmentList.isEmpty
? const NoDataFound().center
: Column(
children: [
AttachmentPicker(
label: context.translation.attachments,
attachment: _attachments,
buttonColor: AppColor.primary10,
onlyImages: false,
showAsListView: true,
// showAsGrid: true,
buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10),
onChange: (attachment) {},
)
.toShadowContainer(
context,
borderRadius: 20,
padding: 12,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
)
.expanded,
Flexible(
fit: FlexFit.loose, // expands only as much as needed
child: Column(
children: [
widget.attachmentType == 5
? AttachmentPicker(
label: context.translation.attachments,
attachment: _attachments,
buttonColor: AppColor.primary10,
onlyImages: false,
showAsListView: true,
buttonIcon: 'quotation_icon'.toSvgAsset(color: AppColor.primary10),
onChange: (attachment) {},
).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
)
: FilesList(images: _attachments.map((e) => URLs.getFileUrl(e.name ?? '') ?? '').toList() ?? []).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
],
),
),
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Save'.addTranslation,
maxWidth: true,
onPressed: () async {
List<GenericAttachmentModel> attachement = [];
for (var item in _attachments) {
String fileName =
CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
attachement.add(GenericAttachmentModel(id: item.id ?? 0, name: fileName));
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
Map<String, dynamic> payLoad = {
'assetDeliveryExternalDeliveryId': widget.tableItemId,
'attachments': attachement,
};
await assetDeliveryProvider.saveAttachment(payload: payLoad).then((status) async {
Navigator.pop(context);
if (status) {
///Need to verify need to stay on this page and refresh or go back..
Navigator.pop(context);
// assetDeliveryProvider.getDeliveryLinesListById(
// itemId: widget.tableItemId,
// );
}
});
}),
buttonColor: AppColor.primary10,
label: 'Save'.addTranslation,
maxWidth: true,
onPressed: _onSavePressed,
),
),
],
),
);
}
Future<void> _onSavePressed() async {
final List<GenericAttachmentModel> attachmentPayload = _attachments.map((item) {
final String name = CMRequestUtils.isLocalUrl(item.name ?? '') ? '${item.name?.split("/").last}|${base64Encode(File(item.name!).readAsBytesSync())}' : item.name ?? '';
return GenericAttachmentModel(
id: item.id ?? 0,
name: name,
);
}).toList();
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const AppLazyLoading(),
);
final payload = {
'assetDeliveryExternalDeliveryId': widget.tableItemId,
'attachments': attachmentPayload,
};
final status = await assetDeliveryProvider.saveAttachment(payload: payload);
Navigator.pop(context);
if (status) {
Navigator.pop(context);
}
}
}

@ -1,5 +1,3 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
@ -10,6 +8,7 @@ import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/cost_center_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
@ -47,8 +46,9 @@ class CostCenterFormView extends StatefulWidget {
}
class _CostCenterFormViewState extends State<CostCenterFormView> {
List<CostCenterModel> _list = [];
CostCenterSerialNoFormModel formModel = CostCenterSerialNoFormModel(costCenters: [], serialNos: []);
late AssetDeliveryProvider assetDeliveryProvider;
CostCenterType _selectedType = CostCenterType.costCenter;
@override
void initState() {
@ -60,15 +60,20 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
}
void getInitialData() async {
_list = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines(
formModel = await assetDeliveryProvider.getAssetDeliveryCostCenterListForLines(
lineId: widget.lineId,
tableItemId: widget.tableItemId,
);
if (_list.isEmpty) {
_list.add(CostCenterModel(
if (formModel.costCenters!.isEmpty) {
formModel.costCenters!.add(CostCenterModel(
id: 0,
));
}
// if (formModel.serialNos!.isEmpty) {
// formModel.serialNos!.add(SerialNoModel(
// id: 0,
// ));
// }
if (widget.isHmg == true) {
CostCenterProvider costCenterProvider = Provider.of<CostCenterProvider>(context, listen: false);
if (costCenterProvider.items.isEmpty) {
@ -78,21 +83,21 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
setState(() {});
}
void _addNewEntry() {
void addItem<T>(List<T> list, T Function() creator) {
setState(() {
_list.add(CostCenterModel(costCenter: Lookup()));
list.add(creator());
});
}
void _removeEntry(int index) {
void removeItem<T>(List<T> list, int index) {
setState(() {
_list.removeAt(index);
list.removeAt(index);
});
}
void _updateModel(int index, void Function(CostCenterModel model) updateList) {
void updateItem<T>(List<T> list, int index, void Function(T item) updater) {
setState(() {
updateList(_list[index]);
updater(list[index]);
});
}
@ -111,34 +116,9 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
? const CircularProgressIndicator(color: AppColor.primary10).center
: Column(
children: [
itemDetails(context: context, itemNo: widget.itemNo, itemDescription: widget.itemDescription),
ListView.builder(
itemCount: _list.length + 1,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
itemBuilder: (context, index) {
if (index == _list.length) {
return AppFilledButton(
label: "Add Cost Center".addTranslation,
maxWidth: true,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addNewEntry,
);
}
return CostCenterItemCard(
model: _list[index],
index: index,
isReadOnly: false,
isHmg: widget.isHmg,
requestId: widget.requestId,
onUpdate: (updateList) => _updateModel(index, updateList),
onRemove: () => _removeEntry(index),
);
},
).expanded,
itemDetails(),
selectionButton(),
_selectedType == CostCenterType.costCenter ? _buildCostCenterList() : _buildSerialNumberList(),
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
@ -147,7 +127,9 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
maxWidth: true,
onPressed: () async {
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await assetDeliveryProvider.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: _list).then((status) async {
await assetDeliveryProvider
.saveCostCenterToLineDeliveryInspection(tableItemId: widget.tableItemId, lineId: widget.lineId, list: formModel.costCenters, serialNoList: formModel.serialNos)
.then((status) async {
Navigator.pop(context);
if (status) {
Navigator.pop(context);
@ -163,40 +145,169 @@ class _CostCenterFormViewState extends State<CostCenterFormView> {
}),
);
}
}
Widget itemDetails({required BuildContext context, String? itemNo, String? itemDescription}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Item No'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
),
8.height,
Text(
itemNo ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
8.height,
Text(
'Item Description'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
Widget _buildCostCenterList() {
return ListView.builder(
itemCount: formModel.costCenters!.length + 1,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
itemBuilder: (context, index) {
if (index == formModel.costCenters!.length) {
return AppFilledButton(
label: "Add Cost Center".addTranslation,
maxWidth: true,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () {
addItem(formModel.costCenters!, () => CostCenterModel(costCenter: Lookup()));
},
);
}
return CostCenterItemCard(
model: formModel.costCenters![index],
index: index,
isReadOnly: false,
isHmg: widget.isHmg,
requestId: widget.requestId,
onUpdate: (update) {
updateItem<CostCenterModel>(formModel.costCenters!, index, update);
},
onRemove: () {
removeItem<CostCenterModel>(formModel.costCenters!, index);
},
);
},
).expanded;
}
Widget _buildSerialNumberList() {
return ListView.builder(
itemCount: formModel.serialNos!.length + 1,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16, top: 8),
itemBuilder: (context, index) {
if (index == formModel.serialNos!.length) {
return AppFilledButton(
label: "Add Serial Number".addTranslation,
maxWidth: true,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: () {
addItem(formModel.serialNos!, () => SerialNoModel());
},
);
}
return SerialNumberItemCard(
model: formModel.serialNos![index],
onUpdate: (update) {
updateItem<SerialNoModel>(formModel.serialNos!, index, update);
},
onRemove: () {
removeItem<SerialNoModel>(formModel.serialNos!, index);
},
);
},
).expanded;
}
Widget selectionButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: [
Expanded(
child: _radioItem(
value: CostCenterType.costCenter,
groupValue: _selectedType,
title: 'Cost Center',
onTap: () {
setState(() {
_selectedType = CostCenterType.costCenter;
});
},
),
),
Expanded(
child: _radioItem(
value: CostCenterType.serialNumber,
groupValue: _selectedType,
title: 'Serial Number',
onTap: () {
setState(() {
_selectedType = CostCenterType.serialNumber;
});
},
),
),
],
),
8.height,
Text(
itemDescription ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
);
}
Widget _radioItem({
required CostCenterType value,
required CostCenterType groupValue,
required String title,
required VoidCallback onTap,
}) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: Row(
children: [
Radio<CostCenterType>(
value: value,
groupValue: groupValue,
onChanged: (_) => onTap(),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
),
4.width,
title.addTranslation.bodyText(context),
],
),
],
).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
showShadow: false,
margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8),
);
);
}
Widget itemDetails() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Item No'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
),
8.height,
Text(
widget.itemNo ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
8.height,
Text(
'Item Description'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10),
),
8.height,
Text(
widget.itemDescription ?? '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
),
],
).toShadowContainer(
context,
borderRadius: 20,
padding: 12,
showShadow: false,
margin: const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 8),
);
}
}
class CostCenterItemCard extends StatelessWidget {
@ -294,3 +405,53 @@ class CostCenterItemCard extends StatelessWidget {
).toShadowContainer(context, paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12)).paddingOnly(bottom: 12);
}
}
class SerialNumberItemCard extends StatelessWidget {
final SerialNoModel model;
final VoidCallback onRemove;
final void Function(void Function(SerialNoModel model)) onUpdate;
const SerialNumberItemCard({
super.key,
required this.model,
required this.onRemove,
required this.onUpdate,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
'Serial Number'.addTranslation.bodyText(context),
Container(
height: 28,
width: 28,
padding: const EdgeInsets.all(6),
child: "trash".toSvgAsset(height: 20, width: 20),
).onPress(onRemove),
],
),
8.height,
AppTextFormField(
labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.serialNo ?? '',
textAlign: TextAlign.center,
showShadow: false,
onChange: (value) {
model.serialNo = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
],
)
.toShadowContainer(
context,
paddingObject: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
)
.paddingOnly(bottom: 12);
}
}

@ -1,5 +1,5 @@
import 'dart:developer';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
@ -7,21 +7,24 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inspection_lines_list_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/attachment_type_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../../new_views/common_widgets/app_filled_button.dart';
@ -110,9 +113,16 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
),
8.height,
Text(
model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
formatInspectionDuration(model.totalTime),
style: AppTextStyles.bodyText2.copyWith(
color: context.isDark ? AppColor.neutral30 : AppColor.neutral120,
),
),
// Text(
// model.totalTime != null ? '${model.totalTime.toString()} hours' : '-',
// style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral120),
// ),
8.height,
const Divider().defaultStyle(context),
Text(
@ -129,7 +139,13 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
child: !viewOnly
? Column(
children: [
AppFilledButton(buttonColor: AppColor.primary10, label: 'Attachments'.addTranslation, maxWidth: true, onPressed: _attachmentTap),
AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Attachments'.addTranslation,
maxWidth: true,
onPressed: () {
HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
}),
16.height,
Row(
children: [
@ -194,69 +210,132 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
}
void calculateTotalTime() {
if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) {
final from = model.deliveryInspectionInspectedDateFrom;
final to = model.deliveryInspectionInspectedDateTo;
if (from == null || to == null) {
model.totalTime = null;
return;
}
final diffInSeconds = to.difference(from).inSeconds;
if (diffInSeconds < 0) {
model.totalTime = null;
return;
}
final fromDate = model.deliveryInspectionInspectedDateFrom!;
final toDate = model.deliveryInspectionInspectedDateTo!;
final hours = toDate.difference(fromDate).inSeconds / 3600.0;
final hours = diffInSeconds / 3600;
model.totalTime = num.parse(hours.toStringAsFixed(3));
}
Widget inspectionDetailsForm() {
return Column(
children: [
if (widget.requestModel?.isHMG == true) ...[
OracleUserAutoCompleteField(
clearAfterPick: false,
initialValue: model.deliveryInspectionInspectedBy ?? '',
label: 'Inspected by'.addTranslation,
onPick: (value) {
model.deliveryInspectionInspectedBy = value.fullName;
setState(() {});
},
onChanged: (value) {},
),
8.height,
OracleUserAutoCompleteField(
clearAfterPick: false,
initialValue: model.deliveryInspectionApprovedBy ?? '',
label: 'Approved by'.addTranslation,
onChanged: (value) {},
onPick: (value) {
model.deliveryInspectionApprovedBy = value.fullName;
setState(() {});
},
),
] //No HMG user free text insted of dropdown ...
else ...[
AppTextFormField(
labelText: 'Inspected by'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.deliveryInspectionInspectedBy ?? '',
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
onChange: (value) {
model.deliveryInspectionInspectedBy = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
_inspectionTile(
title: 'Inspected by'.addTranslation,
model: model.inspectedByModel,
isHmg: widget.requestModel?.isHMG == true,
onTap: () async {
final result = await showInspectionBottomSheet(
context,
title: 'Inspected by'.addTranslation,
isHmg: widget.requestModel?.isHMG == true,
initialModel: model.inspectedByModel ?? InspectionPersonModel(),
);
if (result != null) {
setState(() => model.inspectedByModel = result);
}
},
),
8.height,
_inspectionTile(
title: 'Approved by'.addTranslation,
model: model.approvedByModel,
isHmg: widget.requestModel?.isHMG == true,
onTap: () async {
final result = await showInspectionBottomSheet(
context,
title: 'Approved by'.addTranslation,
isHmg: widget.requestModel?.isHMG == true,
initialModel: model.approvedByModel ?? InspectionPersonModel(),
);
if (result != null) {
setState(() => model.approvedByModel = result);
}
},
),
if (widget.requestModel?.paymentTerm?.value == 2) ...[
8.height,
AppTextFormField(
labelText: 'Approved by'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.deliveryInspectionApprovedBy ?? '',
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
onChange: (value) {
model.deliveryInspectionApprovedBy = value;
_inspectionTile(
title: 'Third Approved by'.addTranslation,
model: model.thirdApprovalModel,
isHmg: widget.requestModel?.isHMG == true,
onTap: () async {
final result = await showInspectionBottomSheet(
context,
title: 'Third Approved by'.addTranslation,
isHmg: widget.requestModel?.isHMG == true,
initialModel: model.thirdApprovalModel ?? InspectionPersonModel(),
);
if (result != null) {
setState(() => model.thirdApprovalModel = result);
}
},
style: Theme.of(context).textTheme.titleMedium,
),
],
// if (widget.requestModel?.isHMG == true) ...[
// OracleUserAutoCompleteField(
// clearAfterPick: false,
// initialValue: model.deliveryInspectionInspectedBy ?? '',
// label: 'Inspected by'.addTranslation,
// onPick: (value) {
// model.deliveryInspectionInspectedBy = value.fullName;
// setState(() {});
// },
// onChanged: (value) {},
// ),
// 8.height,
// OracleUserAutoCompleteField(
// clearAfterPick: false,
// initialValue: model.deliveryInspectionApprovedBy ?? '',
// label: 'Approved by'.addTranslation,
// onChanged: (value) {},
// onPick: (value) {
// model.deliveryInspectionApprovedBy = value.fullName;
// setState(() {});
// },
// ),
// ] //No HMG user free text insted of dropdown ...
// else ...[
// AppTextFormField(
// labelText: 'Inspected by'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: model.deliveryInspectionInspectedBy ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// showShadow: false,
// onChange: (value) {
// model.deliveryInspectionInspectedBy = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// AppTextFormField(
// labelText: 'Approved by'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: model.deliveryInspectionApprovedBy ?? '',
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// showShadow: false,
// onChange: (value) {
// model.deliveryInspectionApprovedBy = value;
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// ],
8.height,
ADatePicker(
label: 'Inspected Date/Time From'.addTranslation,
@ -266,52 +345,31 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
date: model.deliveryInspectionInspectedDateFrom,
from: DateTime(DateTime.now().year, 1, 1),
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
onDatePicker: (selectedDate) async {
final selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget? child) {
final ThemeData currentTheme = Theme.of(context);
return Theme(
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData(
dialHandColor: AppColor.primary10,
dialBackgroundColor: Colors.grey.withOpacity(0.1),
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
entryModeIconColor: AppColor.primary10,
),
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
),
child: child!,
);
},
).then((selectedTime) {
if (selectedTime != null) {
model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
// calculateTotalTime();
///need to check if need validation or not.
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
// "Start time is before the request time.".showToast;
// _pickerStartAt = null;
// selectedTime = null;
// return;
// }
if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) {
"Start time is after than current time".showToast;
model.deliveryInspectionInspectedDateFrom = null;
selectedTime = null;
return;
}
setState(() {});
}
});
builder: _timePickerThemeBuilder,
);
if (selectedTime == null) return;
final fromDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) {
return; // invalid, do not assign
}
model.deliveryInspectionInspectedDateFrom = fromDateTime;
setState(() {});
},
),
8.height,
ADatePicker(
label: 'Inspected Date/Time To'.addTranslation,
@ -321,55 +379,120 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
date: model.deliveryInspectionInspectedDateTo,
from: model.deliveryInspectionInspectedDateFrom,
formatDateWithTime: true,
onDatePicker: (selectedDate) {
showTimePicker(
onDatePicker: (selectedDate) async {
if (model.deliveryInspectionInspectedDateFrom == null) {
"Please select time to first".showToast;
return;
}
final selectedTime = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (BuildContext context, Widget? child) {
final ThemeData currentTheme = Theme.of(context);
return Theme(
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData(
dialHandColor: AppColor.primary10,
dialBackgroundColor: Colors.grey.withOpacity(0.1),
hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)),
dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent),
dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10),
dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)),
entryModeIconColor: AppColor.primary10,
),
textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)),
),
child: child!,
);
},
).then((selectedTime) {
if (selectedTime != null) {
model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute);
calculateTotalTime();
///Need to check need validation or not..
// if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) {
// "Start time is before the request time.".showToast;
// _pickerStartAt = null;
// selectedTime = null;
// return;
// }
if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) {
"End time is after than current time".showToast;
model.deliveryInspectionInspectedDateTo = null;
selectedTime = null;
return;
}
setState(() {});
}
});
builder: _timePickerThemeBuilder,
);
if (selectedTime == null) return;
final toDateTime = DateTime(
selectedDate.year,
selectedDate.month,
selectedDate.day,
selectedTime.hour,
selectedTime.minute,
);
if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) {
return; // invalid, do not assign
}
model.deliveryInspectionInspectedDateTo = toDateTime;
setState(() {});
},
),
],
);
}
bool _validateInspectionDates({DateTime? from, DateTime? to}) {
if (from == null && to == null) return true;
if (from != null) {
if (from.isAfter(DateTime.now())) {
"Time From cannot be in the future".showToast;
return false;
}
if (to != null && from.isAfter(to)) {
"Time To cannot be after Time From".showToast;
return false;
}
}
if (to != null) {
if (to.isAfter(DateTime.now())) {
"Time To cannot be in the future".showToast;
return false;
}
if (from != null && to.isBefore(from)) {
"Timer To cannot be before from time".showToast;
return false;
}
}
if (from != null && to != null) {
final diffInSeconds = to.difference(from).inSeconds;
if (diffInSeconds < 0) {
model.totalTime = null;
return false;
}
final hours = diffInSeconds / 3600.0;
model.totalTime = num.parse(hours.toStringAsFixed(3));
} else {
model.totalTime = null;
}
return true;
}
String formatInspectionDuration(num? hours) {
if (hours == null) return '-';
if (hours < 1) {
final minutes = (hours * 60).round();
return '$minutes minutes';
}
return '${hours.toStringAsFixed(2)} hours';
}
Widget _timePickerThemeBuilder(BuildContext context, Widget? child) {
final ThemeData currentTheme = Theme.of(context);
return Theme(
data: currentTheme.copyWith(
timePickerTheme: TimePickerThemeData(
dialHandColor: AppColor.primary10,
dialBackgroundColor: Colors.grey.withOpacity(0.1),
hourMinuteColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1),
),
dayPeriodColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent,
),
dayPeriodTextColor: MaterialStateColor.resolveWith(
(states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10,
),
dayPeriodBorderSide: BorderSide(
color: Colors.grey.withOpacity(0.2),
),
entryModeIconColor: AppColor.primary10,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColor.primary10,
),
),
),
child: child!,
);
}
Widget inspectionDetails() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -417,13 +540,69 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
);
}
void _attachmentTap() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: widget.deliveryTableModel.id,
)));
Widget _inspectionTile({
required String title,
InspectionPersonModel? model,
required bool isHmg,
required VoidCallback onTap,
}) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppTextStyles.textFieldLabelStyle),
6.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
model?.name?.isNotEmpty == true ? model!.name! : 'Tap to add'.addTranslation,
style: AppTextStyles.bodyText,
),
///Need to display other info as well
// Text(
// model?.email?.isNotEmpty == true
// ? model!.email!
// : '',
// style: AppTextStyles.bodyText,
// ),
],
),
],
),
],
),
),
);
}
Future<Lookup?> showAttachmentTypePicker() {
return showDialog<Lookup>(
context: context,
builder: (_) {
return AlertDialog(
content: SingleItemDropDownMenu<Lookup, AttachmentTypeLookupProvider>(
context: context,
title: context.translation.reason,
showAsFullScreenDialog: false,
onSelect: (value) {
Navigator.pop(context, value);
},
),
);
},
);
}
void _cancelTap() async {
@ -469,4 +648,40 @@ class _DeliveryInspectionFormViewState extends State<DeliveryInspectionFormView>
}
});
}
Future<InspectionPersonModel?> showInspectionBottomSheet(
BuildContext context, {
required String title,
required bool isHmg,
required InspectionPersonModel initialModel,
}) {
return showModalBottomSheet<InspectionPersonModel>(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (_) {
if (initialModel.localSignature == null && initialModel.signature != null) {
initialModel.localSignature = signatureFromString(initialModel.signature);
}
return InspectionPersonBottomSheet(
title: title,
isHmg: isHmg,
model: InspectionPersonModel(
name: initialModel.name,
email: initialModel.email,
signature: initialModel.signature,
localSignature: initialModel.localSignature,
),
);
},
);
}
Uint8List? signatureFromString(String? value) {
if (value == null || !value.contains('|')) return null;
final base64Part = value.split('|').last;
return base64Decode(base64Part);
}
}

@ -0,0 +1,152 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/oracle_user_autocomplete_field.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
class InspectionPersonBottomSheet extends StatefulWidget {
final String title;
bool isHmg;
final InspectionPersonModel model;
InspectionPersonBottomSheet({
super.key,
required this.title,
required this.isHmg,
required this.model,
});
@override
State<InspectionPersonBottomSheet> createState() => _InspectionPersonBottomSheetState();
}
class _InspectionPersonBottomSheetState extends State<InspectionPersonBottomSheet> {
late InspectionPersonModel _model;
late TextEditingController nameController;
late TextEditingController emailController;
@override
void initState() {
super.initState();
_model = InspectionPersonModel(name: widget.model.name, email: widget.model.email, signature: widget.model.signature, localSignature: widget.model.localSignature);
nameController = TextEditingController(text: _model.name ?? '');
emailController = TextEditingController(text: _model.email ?? '');
}
@override
void dispose() {
nameController.dispose();
emailController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: Padding(
padding: EdgeInsets.only(
top: 16,
left: 16,
right: 16,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.title, style: Theme.of(context).textTheme.titleLarge),
16.height,
if (widget.isHmg)
OracleUserAutoCompleteField(
clearAfterPick: false,
initialValue: _model.name ?? '',
label: 'Name'.addTranslation,
onPick: (value) {
_model.name = value.fullName;
nameController.text = value.fullName ?? '';
emailController.text = value.employeeEmail ?? '';
setState(() {});
},
)
else
AppTextFormField(
labelText: 'Name'.addTranslation,
controller: nameController,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
onChange: (v) {
_model.name = v;
setState(() {});
},
),
12.height,
AppTextFormField(
labelText: 'Email'.addTranslation,
controller: emailController,
textInputType: TextInputType.emailAddress,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
enable: widget.isHmg?false:true,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
onChange: (v) {
setState(() {
_model.email = v;
});
},
),
12.height,
ESignature(
title: '',
oldSignature: _model.localSignature == null ? _model.signature : null,
newSignature: _model.localSignature,
backgroundColor: AppColor.neutral100,
showShadow: false,
onChange: (signature) {
if (signature.isEmpty) return;
setState(() {
_model.localSignature = signature;
_model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
});
},
onSaved: (signature) {
if (signature == null || signature.isEmpty) return;
setState(() {
_model.localSignature = signature;
_model.signature = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
});
},
),
20.height,
AppFilledButton(
label: context.translation.save,
maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
_model.name = nameController.text.trim();
_model.email = emailController.text.trim();
Navigator.pop(context, _model);
},
),
],
),
),
);
}
}

@ -26,25 +26,26 @@ class OracleUserAutoCompleteField extends StatefulWidget {
class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
AssetDeliveryProvider? assetDeliveryProvider;
late TextEditingController _controller;
// late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
// _controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant OracleUserAutoCompleteField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue);
}
// if (widget.initialValue != oldWidget.initialValue) {
// _controller = TextEditingController(text: widget.initialValue);
// }
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
// _controller.dispose();
super.dispose();
}
@ -59,16 +60,18 @@ class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Autocomplete<OracleUserModel>(
key: ValueKey(widget.initialValue),
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) {
return const Iterable<OracleUserModel>.empty();
}
return await assetDeliveryProvider!.getOracleUserAutoCompleteDetails(query: textEditingValue.text);
},
initialValue: TextEditingValue(text: widget.initialValue),
displayStringForOption: (OracleUserModel option) => option.fullName ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
controller: fieldTextEditingController,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
@ -101,11 +104,11 @@ class _AutoCompletePartsFieldState extends State<OracleUserAutoCompleteField> {
);
},
onSelected: (OracleUserModel selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = selection.fullName ?? '';
}
// if (widget.clearAfterPick) {
// fieldTextEditingController.clear();
// } else {
// _controller.text = selection.fullName ?? '';
// }
widget.onPick(selection);
},
),

@ -90,10 +90,12 @@ class EndUserAssetDetailCard extends StatelessWidget {
'Replaced Asset No: ${assetModel.replacedAssetNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
//TODO Need to confirm with @Ahmed need to hide this or not
if (assetModel.status?.value == 2)
Text(
'Rejection Reason: ${assetModel.rejectionReason?.name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Description: ${assetModel.description ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -5,6 +5,7 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart';
@ -156,12 +157,7 @@ class _EndUserCostCenterLIstViewState extends State<EndUserCostCenterLIstView> {
}
void _attachmentTap() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: widget.deliveryTableModel.id,
)));
HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
}
void _cancelTap() async {

@ -1,6 +1,229 @@
// import 'dart:developer';
//
// import 'package:flutter/foundation.dart';
// import 'package:flutter/material.dart';
// import 'package:provider/provider.dart';
// import 'package:test_sa/extensions/context_extension.dart';
// import 'package:test_sa/extensions/int_extensions.dart';
// import 'package:test_sa/extensions/string_extensions.dart';
// import 'package:test_sa/extensions/text_extensions.dart';
// import 'package:test_sa/extensions/widget_extensions.dart';
// import 'package:test_sa/models/lookup.dart';
// import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/end_user_rejection_reason_lookup_provider.dart';
// import 'package:test_sa/modules/asset_delivery_module/provider/end_user_status_lookup_provider.dart';
// import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
// import 'package:test_sa/new_views/app_style/app_color.dart';
// import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
// import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
// import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
// import '../../../../new_views/common_widgets/app_filled_button.dart';
// import '../../../../new_views/common_widgets/default_app_bar.dart';
//
// class UpdateEndUserAssetDetailsView extends StatefulWidget {
// EndUserAssetDetailsModel? assetDetailsModel;
// String? costCenterName;
// int? tableId;
//
// UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key);
//
// @override
// State<UpdateEndUserAssetDetailsView> createState() => _UpdateEndUserAssetDetailsViewState();
// }
//
// class _UpdateEndUserAssetDetailsViewState extends State<UpdateEndUserAssetDetailsView> {
// final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
// bool viewOnly = false;
// late AssetDeliveryProvider assetDeliveryProvider;
// EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
// late TextEditingController quantityController;
// late TextEditingController descriptionController;
//
// @override
// void initState() {
// quantityController = TextEditingController();
// descriptionController = TextEditingController();
// WidgetsBinding.instance.addPostFrameCallback((_) {
// getInitialData();
// });
// super.initState();
// }
//
// @override
// void dispose() {
// super.dispose();
// }
//
// void getInitialData() async {
// assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false);
// if (widget.assetDetailsModel != null) {
// model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson());
// model.costCenterName = widget.costCenterName;
// model.assetDeliveryExternalDeliveryId = widget.tableId;
// model.status = widget.assetDetailsModel?.status;
// model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
// }
// quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
// descriptionController.text = model.description ?? '';
// model.type = 'Accessory';
// setState(() {});
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// key: _scaffoldKey,
// appBar: DefaultAppBar(
// title: 'Item Details'.addTranslation,
// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
// ),
// body: Form(
// key: _formKey,
// child: Column(
// children: [
// SingleChildScrollView(
// padding: const EdgeInsets.all(16),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Status'.addTranslation,
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// validator: (value) {
// if (value == null) return "Please select status";
// return null;
// },
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.status,
// onSelect: (status) {
// if (status != null) {
// model.status = status;
// setState(() {});
// }
// },
// ),
// 8.height,
// if (model.type == 'Accessory') ...[
// AppTextFormField(
// labelText: 'Rejected Quantity'.addTranslation,
// controller: quantityController,
// backgroundColor: AppColor.fieldBgColor(context),
// textAlign: TextAlign.center,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// textInputType: TextInputType.number,
// showShadow: false,
// validator: (value) {
// if ((value ?? "").isEmpty) return "Mandatory";
// return null;
// },
// onChange: (value) {
// if (value.isNotEmpty) {
// model.rejectedQty = model.rejectedQty = num.tryParse(value);
// setState(() {});
// }
// },
// style: Theme.of(context).textTheme.titleMedium,
// ),
// 8.height,
// if (model.status?.value == 1 && (model.rejectedQty != null && quantityController.text.isNotEmpty && model.rejectedQty! > 0))
// SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Rejection Reason '.addTranslation,
// validator: (value) {
// if (value == null) return "Please select rejection reason";
// return null;
// },
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.rejectionReason,
// onSelect: (reason) {
// if (reason != null) {
// model.rejectionReason = reason;
// setState(() {});
// }
// },
// ),
// 8.height,
// ],
// if (model.status != null && model.status!.value == 2) ...[
// SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: 'Rejection Reason '.addTranslation,
// validator: (value) {
// if (value == null) return "Please select rejection reason";
// return null;
// },
// titleTextColor: AppColor.neutral120,
// showShadow: false,
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: model.rejectionReason,
// onSelect: (reason) {
// if (reason != null) {
// model.rejectionReason = reason;
// setState(() {});
// }
// },
// ),
// 8.height,
// ],
// AppTextFormField(
// controller: descriptionController,
// labelText: 'Description'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
// showShadow: false,
// labelStyle: AppTextStyles.textFieldLabelStyle,
// alignLabelWithHint: true,
// textInputType: TextInputType.multiline,
// onChange: (value) {
// model.description = value;
// },
// onSaved: (value) {
// model.description = value;
// },
// ),
// 8.height,
// ],
// ).toShadowContainer(context, borderRadius: 20, padding: 12))
// .expanded,
// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
// ],
// ),
// ),
// );
// }
//
// ///Need to check which details show here...
//
// void _saveTap() async {
// if (!_formKey.currentState!.validate()) {
// return;
// }
// _formKey.currentState!.save();
// log('payload ${model.toJson()}');
// return;
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
// await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async {
// Navigator.pop(context);
// if (status) {
// Navigator.pop(context, true);
// }
// });
// }
// }
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
@ -22,11 +245,16 @@ import '../../../../new_views/common_widgets/app_filled_button.dart';
import '../../../../new_views/common_widgets/default_app_bar.dart';
class UpdateEndUserAssetDetailsView extends StatefulWidget {
EndUserAssetDetailsModel? assetDetailsModel;
String? costCenterName;
int? tableId;
final EndUserAssetDetailsModel? assetDetailsModel;
final String? costCenterName;
final int? tableId;
UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key);
const UpdateEndUserAssetDetailsView({
Key? key,
this.assetDetailsModel,
this.costCenterName,
this.tableId,
}) : super(key: key);
@override
State<UpdateEndUserAssetDetailsView> createState() => _UpdateEndUserAssetDetailsViewState();
@ -34,147 +262,260 @@ class UpdateEndUserAssetDetailsView extends StatefulWidget {
class _UpdateEndUserAssetDetailsViewState extends State<UpdateEndUserAssetDetailsView> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool viewOnly = false;
late AssetDeliveryProvider assetDeliveryProvider;
EndUserAssetDetailsModel model = EndUserAssetDetailsModel();
late TextEditingController quantityController;
late TextEditingController descriptionController;
@override
void initState() {
super.initState();
quantityController = TextEditingController();
descriptionController = TextEditingController();
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
_loadInitialData();
});
super.initState();
}
@override
void dispose() {
super.dispose();
}
void getInitialData() async {
void _loadInitialData() {
assetDeliveryProvider = Provider.of<AssetDeliveryProvider>(context, listen: false);
if (widget.assetDetailsModel != null) {
model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson());
model = EndUserAssetDetailsModel.fromJson(
widget.assetDetailsModel!.toJson(),
);
model.costCenterName = widget.costCenterName;
model.assetDeliveryExternalDeliveryId = widget.tableId;
model.status = widget.assetDetailsModel?.status;
model.rejectionReason = widget.assetDetailsModel?.rejectionReason;
model.receivedQty = widget.assetDetailsModel?.receivedQty;
}
log('details ${model.toJson()}');
quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : '';
descriptionController.text = model.description ?? '';
setState(() {});
}
bool get _isAccessory => model.type == 'Accessory';
bool get _isAccepted => model.status?.value == 1;
bool get _isRejected => model.status?.value == 2;
bool get _showRejectedQty {
if (_isAccessory) return true;
return false;
}
bool get _showReceivedQty {
if (_isAccessory && model.receivedQty != null) return true;
return false;
}
bool get _showRejectionReason {
if (_isAccessory) {
if (_isRejected) return true;
if (_isAccepted && (model.rejectedQty ?? 0) > 0) return true;
return false;
}
if (_isRejected) return true;
return false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: 'Item Details'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
titleStyle: AppTextStyles.heading3.copyWith(
fontWeight: FontWeight.w500,
color: context.isDark ? AppColor.neutral30 : AppColor.neutral50,
),
),
body: Form(
key: _formKey,
child: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Status'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.status,
onSelect: (status) {
if (status != null) {
model.status = status;
setState(() {});
}
},
),
8.height,
SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Rejection Reason '.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.rejectionReason,
onSelect: (reason) {
if (reason != null) {
model.rejectionReason = reason;
setState(() {});
}
},
),
8.height,
if (model.type == 'Accessory') ...[
AppTextFormField(
labelText: 'Rejected Quantity'.addTranslation,
controller: quantityController,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
onChange: (value) {
if (value.isNotEmpty) {
model.rejectedQty = model.rejectedQty = num.tryParse(value);
}
},
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
],
AppTextFormField(
controller: descriptionController,
labelText: 'Description'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) {
model.description = value;
},
onSaved: (value) {
model.description = value;
},
),
8.height,
],
).toShadowContainer(context, borderRadius: 20, padding: 12))
.expanded,
FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)),
padding: const EdgeInsets.all(16),
child: _formBody(context),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Save'.addTranslation,
maxWidth: true,
onPressed: _saveTap,
),
),
],
),
),
);
}
///Need to check which details show here...
Widget _formBody(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_statusDropdown(),
8.height,
if (_showReceivedQty) ...[
_receivedQtyField(),
8.height,
],
if (_showRejectedQty) ...[
_rejectedQtyField(),
8.height,
],
if (_showRejectionReason) ...[
_rejectionReasonDropdown(),
8.height,
],
_descriptionField(),
8.height,
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
Widget _statusDropdown() {
return SingleItemDropDownMenu<Lookup, EndUserStatusLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Status'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.status,
validator: (value) {
if (value == null) return 'Please select status';
return null;
},
onSelect: (status) {
if (status != null) {
model.status = status;
model.rejectionReason = null;
setState(() {});
}
},
);
}
Widget _rejectedQtyField() {
return AppTextFormField(
labelText: 'Rejected Quantity'.addTranslation,
controller: quantityController,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
validator: (value) {
if (!_showRejectedQty) return null;
if ((value ?? '').isEmpty) return 'Mandatory';
final qty = num.tryParse(value!);
if (qty == null || qty <= 0) return 'Enter valid quantity';
return null;
},
onChange: (value) {
model.rejectedQty = value.isNotEmpty ? num.tryParse(value) : null;
setState(() {});
},
);
}
Widget _receivedQtyField() {
return Container(
padding: const EdgeInsets.all(12),
width: double.infinity,
decoration: BoxDecoration(
color: AppColor.neutral40,
// color: AppColor.fieldBgColor(context),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Received Qty', style: AppTextStyles.textFieldLabelStyle),
4.height,
Text(model.receivedQty.toString(), style: AppTextStyles.textFieldLabelStyle),
],
),
);
AppTextFormField(
labelText: 'Received Quantity'.addTranslation,
initialValue: model.receivedQty.toString(),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
);
}
Widget _rejectionReasonDropdown() {
return SingleItemDropDownMenu<Lookup, EndUserRejectionReasonLookupProvider>(
context: context,
height: 56.toScreenHeight,
title: 'Rejection Reason'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.rejectionReason,
validator: (value) {
if (!_showRejectionReason) return null;
if (value == null) return 'Please select rejection reason';
return null;
},
onSelect: (reason) {
if (reason != null) {
model.rejectionReason = reason;
setState(() {});
}
},
);
}
Widget _descriptionField() {
return AppTextFormField(
controller: descriptionController,
labelText: 'Description'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
onChange: (value) => model.description = value,
onSaved: (value) => model.description = value,
);
}
void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
_formKey.currentState!.save();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async {
Navigator.pop(context);
if (status) {
Navigator.pop(context, true);
}
});
log('payload ${model.toJson()}');
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const AppLazyLoading(),
);
final status = await assetDeliveryProvider.saveEndUserAssetDataData(model: model);
Navigator.pop(context);
if (status) {
Navigator.pop(context, true);
}
}
}

@ -235,16 +235,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
onChanged: (value) {},
),
8.height,
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: false,
style: Theme.of(context).textTheme.titleMedium,
),
] else ...[
AppTextFormField(
labelText: 'Accepted By'.addTranslation,
@ -253,25 +243,34 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onChange: (value) {
model.acceptedBy = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
onChange: (value) {
model.acceptedByEmail = value;
},
style: Theme.of(context).textTheme.titleMedium,
),
],
AppTextFormField(
labelText: 'Accepted By Email'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: acceptedByEmailController,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onChange: (value) {
model.acceptedByEmail = value;
},
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
enable: widget.isHmg == true ? false : true,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
ESignature(
title: 'End User Signature',
@ -280,11 +279,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
backgroundColor: AppColor.neutral100,
showShadow: false,
onChange: (signature) {
log('onChange called.');
updateSignature(signature: signature);
},
onSaved: (signature) {
log('onSaved called.');
updateSignature(signature: signature);
},
)
@ -294,7 +288,10 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
void updateSignature({Uint8List? signature}) {
if (signature == null || signature.isEmpty) {
model.acceptedBySignature = '';
setState(() {
newSignature = null;
model.acceptedBySignature = null;
});
return;
}
setState(() {
@ -304,6 +301,23 @@ class _UpdateEndUserCostCenterDetailsViewState extends State<UpdateEndUserCostCe
}
void _saveTap() async {
if (!_formKey.currentState!.validate()) {
return;
}
if (model.acceptanceDate == null) {
"Select Accepted date".showToast;
return;
}
if (widget.isHmg == true) {
if ((model.acceptedBy ?? '').isEmpty || (model.acceptedByEmail ?? '').isEmpty) {
'Accepted By and Email are required'.addTranslation.showToast;
return;
}
}
if (model.acceptedBySignature == null || model.acceptedBySignature!.isEmpty) {
'Signature is required'.addTranslation.showToast;
return;
}
_formKey.currentState!.save();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
model.assetDeliveryExternalDetailId = widget.tableItemId;

@ -7,7 +7,7 @@ import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';

@ -75,6 +75,14 @@ class TechnicalInspectionAssetCard extends StatelessWidget {
'Asset Number: ${assetModel.assetNumber ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Model: ${assetModel.modelDefinition?.model ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Manufacturer: ${assetModel.modelDefinition?.manufacturer ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'Serial Number: ${assetModel.serialNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),

@ -8,6 +8,7 @@ import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/asset_delivery_module/helper_function.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart';
@ -224,12 +225,13 @@ class _TechnicalInspectionLinesListViewState extends State<TechnicalInspectionLi
}
void _attachmentTap() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AssetDeliveryAttachmentView(
tableItemId: widget.deliveryTableModel.id,
)));
HelperFunction.attachmentTap(context: context, assetDeliveryProvider: assetDeliveryProvider!, deliveryTableItemId: widget.deliveryTableModel.id);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => AssetDeliveryAttachmentView(
// tableItemId: widget.deliveryTableModel.id,
// )));
}
void _cancelTap() async {

@ -10,7 +10,7 @@ import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
import 'package:test_sa/modules/asset_delivery_module/provider/asset_delivery_provider.dart';
@ -189,11 +189,48 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
}
}),
8.height,
AppTextFormField(
labelText: 'Asset Name'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.assetName,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Model'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.model,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Manufacturer'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.manufacturer ?? '',
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: serialNoCtrl,
initialValue: model.serialNo ?? '',
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
@ -346,7 +383,13 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
///Need to check which details show here...
void _saveTap() async {
if(!_formKey.currentState!.validate()) return;
if(assetDeliveryProvider.childFormModel.installationDate==null){
"Installation Date is Required".showToast;
return;
}
_formKey.currentState!.save();
//Need to check if not auto update.
// assetDeliveryProvider.parentFormModel.childAssetList?[widget.index]= assetDeliveryProvider.childFormModel;
Navigator.pop(context);
@ -423,6 +466,10 @@ class _UpdateChildAssetViewState extends State<UpdateChildAssetView> {
}
String _statusFromBool(bool? value) {
return value == true ? 'PASS' :value==false? 'FAIL':'';
return value == true
? 'PASS'
: value == false
? 'FAIL'
: '';
}
}

@ -10,7 +10,7 @@ import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_delivery_module/models/technical_inspection_asset_model.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_utils.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/search_asset_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/status_checklist_view.dart';
import 'package:test_sa/modules/asset_delivery_module/pages/technical_inpection/technical_inpection_asset_card_view.dart';
@ -216,20 +216,64 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
if (assetModel.site != null) {
await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel);
}
assetModel.assetDeliveryInternalDetailAssetId = assetModel.id;
assetModel.id = 0;
assetModel.assetDeliveryInternalDetailAssetId = assetModel.id;
assetModel.id = 0;
if (assetModel.childAssetList != null && assetModel.childAssetList!.isNotEmpty) {
for (var asset in assetModel.childAssetList!) {
asset.assetDeliveryInternalDetailAssetChildId = asset.id;
asset.id = 0;
}
}
provider.setParentModel(assetModel);
log('child list length ${assetModel.childAssetList?.length}');
populateTextFields(model: provider.parentFormModel);
}
}
}),
8.height,
AppTextFormField(
labelText: 'Asset Name'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.assetName,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Model'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.model,
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Manufacturer'.addTranslation,
// backgroundColor: AppColor.fieldBgColor(context),
initialValue: model.modelDefinition?.manufacturer ?? '',
textAlign: TextAlign.center,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
style: Theme.of(context).textTheme.titleMedium,
),
8.height,
AppTextFormField(
labelText: 'Serial Number'.addTranslation,
backgroundColor: AppColor.fieldBgColor(context),
controller: serialNoCtrl,
initialValue: model.serialNo ?? '',
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
@ -384,6 +428,11 @@ class _UpdateParentAssetViewState extends State<UpdateParentAssetView> {
///Need to check which details show here...
void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
if (assetDeliveryProvider.parentFormModel.installationDate == null) {
"Installation Date is Required".showToast;
return;
}
_formKey.currentState!.save();
assetDeliveryProvider.parentFormModel.lineId = widget.lineId;

@ -179,6 +179,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
title: 'Power Supply Type'.addTranslation,
titleTextColor: AppColor.neutral120,
showShadow: false,
validator: (value) {
if (value == null) return 'Please select power supply type';
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
initialValue: model.powerSupplyType,
@ -198,6 +202,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) {
model.powerReading = int.tryParse(value);
},
@ -212,6 +220,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
labelStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.number,
showShadow: false,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) {
model.maxCurrent = int.tryParse(value);
},
@ -224,6 +236,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
textInputType: TextInputType.number,
initialValue: model.voltage != null ? model.voltage.toString() : '',
textAlign: TextAlign.center,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) {
model.voltage = int.tryParse(value);
},
@ -238,6 +254,10 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
initialValue: model.frequency != null ? model.frequency.toString() : '',
textInputType: TextInputType.number,
textAlign: TextAlign.center,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
onSaved: (value) {
model.frequency = int.tryParse(value);
},
@ -250,6 +270,7 @@ class _UpdateTechnicalInspectionLinesViewState extends State<UpdateTechnicalInsp
}
void _saveTap() async {
if (!_formKey.currentState!.validate()) return;
_formKey.currentState!.save();
model.tableItemId = widget.deliveryTableModel.id;
model.lineId = widget.deliveryLineModel?.id;

@ -11,6 +11,7 @@ import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/cost_center_serial_no_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection_form_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart';
import 'package:test_sa/modules/asset_delivery_module/models/end_user_asset_details_model.dart';
@ -171,33 +172,38 @@ class AssetDeliveryProvider extends ChangeNotifier {
}
}
Future<List<CostCenterModel>> getAssetDeliveryCostCenterListForLines({int? lineId, int? tableItemId}) async {
List<CostCenterModel> costCenterList = [];
Future<CostCenterSerialNoFormModel> getAssetDeliveryCostCenterListForLines({
int? lineId,
int? tableItemId,
}) async {
CostCenterSerialNoFormModel costCenterSerialNoFormModel = CostCenterSerialNoFormModel();
try {
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.get(
"${URLs.getCostCenterListToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId",
"${URLs.getCostCenterAndSerialNoToLineDeliveryInspection}?AssetDeliveryExternalDetailId=$lineId&AssetDeliveryExternalDeliveryId=$tableItemId",
);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final jsonData = json.decode(response.body)["data"];
if (jsonData is List) {
costCenterList = jsonData.map((e) => CostCenterModel.fromJson(e)).toList();
}
costCenterSerialNoFormModel = CostCenterSerialNoFormModel.fromJson(jsonData);
} else {
costCenterList = [];
costCenterSerialNoFormModel.costCenters = [];
costCenterSerialNoFormModel.serialNos = [];
}
isLoading = false;
notifyListeners();
return costCenterList;
} catch (e) {
log("get Delivery Lines List [error] : $e");
costCenterSerialNoFormModel.costCenters = [];
costCenterSerialNoFormModel.serialNos = [];
} finally {
isLoading = false;
costCenterList = [];
notifyListeners();
return costCenterList;
}
return costCenterSerialNoFormModel;
}
Future<bool> addNewDelivery({
@ -253,15 +259,17 @@ class AssetDeliveryProvider extends ChangeNotifier {
int? tableItemId,
int? lineId,
List<CostCenterModel>? list,
List<SerialNoModel>? serialNoList,
}) async {
isLoading = true;
Map<String, dynamic> payload = {
"assetDeliveryExternalDeliveryId": tableItemId,
"assetDeliveryExternalDetailId": lineId,
"costCenters": list?.map((x) => x.toJson()).toList(),
if (serialNoList != null && serialNoList.isNotEmpty) "serialNos": serialNoList.map((x) => x.toJson()).toList(),
};
try {
final response = await ApiManager.instance.post(URLs.saveCostCenterToLineDeliveryInspection, body: payload);
final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
@ -421,10 +429,11 @@ class AssetDeliveryProvider extends ChangeNotifier {
Future<List<GenericAttachmentModel>> getAttachments({
num? tableItemId,
num? attachmentType,
}) async {
try {
isLoading = true;
final response = await ApiManager.instance.get("${URLs.getAttachments}?assetDeliveryExternalDeliveryId=$tableItemId");
final response = await ApiManager.instance.get("${URLs.getAttachments}?attachmentDocTypeValue=$attachmentType&assetDeliveryExternalDeliveryId=$tableItemId");
List<GenericAttachmentModel> list = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
class AttachmentTypeLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.attachmentTypeLookup);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -18,13 +18,12 @@ class AppBottomNavigationBar extends StatelessWidget {
Widget build(BuildContext context) {
bool isEngineer = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.engineer;
bool isUserFMS = Provider.of<SettingProvider>(context, listen: false).isUserFMS;
bool commissioningEng = context.userProvider.isCommissioningEngineer;
List<NavItemModel> navItems = [
NavItemModel(0, "overview", context.translation.overview),
NavItemModel(1, "request_icon", context.translation.workOrder),
//TODO unCommit this to disable task
// if (!isEngineer||isUserFMS)
NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false),
if (!commissioningEng) NavItemModel(2, "add_icon", context.translation.calendar, showLabel: false),
NavItemModel(3, "assets", context.translation.assets),
NavItemModel(4, "contact", context.translation.contact),
];

@ -106,6 +106,12 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
types['Equipment Internal Audit'] = 10;
types['System Internal Audit'] = 11;
}
if (context.userProvider.isCommissioningEngineer) {
///TODO need to check what other requests type needed here.
types = {
'Asset Delivery': 13,
};
}
final statuses = {
"All WO": 0,

@ -69,7 +69,7 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
requestsList.add(Request(10, 'Equipment Internal Audit'));
requestsList.add(Request(11, 'System Internal Audit'));
//Need to be added for new user role commissioning engineer
requestsList.add(Request(13, "Asset Delivery"));
// requestsList.add(Request(13, "Asset Delivery"));
}
requestsList.add(Request(12, "Loan Equipment"));
@ -80,6 +80,13 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
Request(9, 'TRAF'),
];
}
if (context.userProvider.isCommissioningEngineer) {
///TODO need to show only allowed ids for all workOrder
requestsList = [
Request(null, context.translation.allWorkOrder),
Request(13, "Asset Delivery"),
];
}
if (context.userProvider.isQualityUser) {
requestsList = [
Request(null, context.translation.allWorkOrder),

Loading…
Cancel
Save