asset inventory module ready for qa

design_3.0_asset_inventory_module
WaseemAbbasi22 3 weeks ago
parent c19fdb173b
commit 8578319cc3

@ -1,144 +0,0 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/app_style/sizing.dart';
class AutoCompleteGenericField<T extends Object> extends StatefulWidget {
final String? label;
final String initialValue;
final bool clearAfterPick;
final Future<List<T>> Function(String query) onSearch;
final String Function(T item) displayString;
final Function(T item) onPick;
const AutoCompleteGenericField({
Key? key,
this.label,
required this.initialValue,
required this.onSearch,
required this.displayString,
required this.onPick,
this.clearAfterPick = true,
}) : super(key: key);
@override
State<AutoCompleteGenericField<T>> createState() => _AutoCompleteGenericFieldState<T>();
}
class _AutoCompleteGenericFieldState<T extends Object> extends State<AutoCompleteGenericField<T>> {
late TextEditingController _controller;
List<T> _options = [];
bool _isLoading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompleteGenericField<T> oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller.text = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}
Future<void> _search(String query) async {
if (query.isEmpty) {
setState(() => _options = []);
return;
}
setState(() => _isLoading = true);
try {
final results = await widget.onSearch(query);
setState(() => _options = results);
} finally {
setState(() => _isLoading = false);
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
return Container(
decoration: BoxDecoration(
color: AppColor.background(context),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: RawAutocomplete<T>(
// textEditingController: _controller,
optionsBuilder: (TextEditingValue textEditingValue) => _options,
displayStringForOption: widget.displayString,
fieldViewBuilder: (context, fieldTextEditingController, fieldFocusNode, onFieldSubmitted) {
return TextField(
controller: _controller,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
decoration: InputDecoration(
border: border,
disabledBorder: border,
focusedBorder: border,
enabledBorder: border,
errorBorder: border,
contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
// suffixIcon: _isLoading
// ? const Padding(
// padding: EdgeInsets.all(8.0),
// child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)),
// )
// : const Icon(Icons.search, size: 18),
filled: true,
fillColor: AppColor.fieldBgColor(context),
labelText: widget.label,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
),
textInputAction: TextInputAction.search,
onChanged: (text) => _search(text),
onSubmitted: (_) => onFieldSubmitted(),
);
},
onSelected: (T selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = widget.displayString(selection);
}
widget.onPick(selection);
},
optionsViewBuilder: (context, onSelected, options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(10),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200, minWidth: 200),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
itemBuilder: (context, index) {
final option = options.elementAt(index);
return ListTile(
title: Text(widget.displayString(option)),
onTap: () => onSelected(option),
);
},
),
),
),
);
},
),
);
}
}

@ -0,0 +1,124 @@
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/models/lookup.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../extensions/text_extensions.dart';
import '../../../new_views/app_style/app_text_style.dart';
class LookUpAutoCompleteField extends StatefulWidget {
final String initialValue;
final String label;
final num? assetId;
final bool forAssetName;
final bool forSupplier;
final bool clearAfterPick, isManufacturer;
final Function(Lookup) onPick;
final Function(String) onChanged;
//need to pass directly url
const LookUpAutoCompleteField(
{Key? key,
this.isManufacturer = false,
required this.initialValue,
required this.label,
this.forAssetName = false,
this.forSupplier = false,
this.assetId,
required this.onPick,
this.clearAfterPick = true,
required this.onChanged})
: super(key: key);
@override
_AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState();
}
class _AutoCompletePartsFieldState extends State<LookUpAutoCompleteField> {
AssetInventoryProvider? assetInventoryProvider;
late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant LookUpAutoCompleteField oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller = TextEditingController(text: widget.initialValue);
}
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
assetInventoryProvider ??= Provider.of<AssetInventoryProvider>(context);
final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
return Container(
decoration: BoxDecoration(
color: AppColor.background(context),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
),
child: Autocomplete<Lookup>(
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) {
return const Iterable<Lookup>.empty();
}
return (await assetInventoryProvider!.getAutoCompleteDetails(query: textEditingValue.text, isManufacturer: widget.isManufacturer, type: widget.forAssetName?1:widget.forSupplier?2:0));
},
displayStringForOption: (Lookup option) => option.name ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
decoration: InputDecoration(
border: border,
disabledBorder: border,
focusedBorder: border,
enabledBorder: border,
errorBorder: border,
contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
constraints: const BoxConstraints(),
suffixIconConstraints: const BoxConstraints(minWidth: 0),
filled: true,
fillColor: AppColor.fieldBgColor(context),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
labelText: widget.label,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
),
textInputAction: TextInputAction.search,
onChanged: (text) {
widget.onChanged(text);
fieldTextEditingController.text = text;
},
onSubmitted: (String value) {
onFieldSubmitted();
},
);
},
onSelected: (Lookup selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = selection.name ?? '';
}
widget.onPick(selection);
},
),
);
}
}

@ -298,7 +298,24 @@ class URLs {
// asset inventory Urls. // asset inventory Urls.
static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById'; static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById';
static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion'; static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion';
static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter'; static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter';
static get searchAsset => '$_baseUrl/AssetInventory/SearchAsset';
static get saveAssetInSession => '$_baseUrl/AssetInventory/SaveAssetInSession';
static get deleteAssetInSession => '$_baseUrl/AssetInventory/DeleteAssetInSession';
static get getManufacturerOrModelAutoComplete => '$_baseUrl/AssetInventory/GetManufacturerOrModelAutoComplete';
static get searchAssetName => '$_baseUrl/AssetInventory/SearchAssetName';
static get getSuppliersAutoCompleteInventory => '$_baseUrl/Supplier/GetSuppliersMobile';
static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp';
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
} }

@ -48,7 +48,6 @@ class GasRefillCommentsProvider extends ChangeNotifier {
late Response response; late Response response;
try { try {
response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId"); response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId");
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
List requestsListJson = json.decode(response.body)["data"]; List requestsListJson = json.decode(response.body)["data"];

@ -123,11 +123,14 @@ class RequestsDetails {
String? statusReceiver; String? statusReceiver;
String? assetTransferFrom; String? assetTransferFrom;
String? assetTransferTo; String? assetTransferTo;
String? sessionType;
String? code; String? code;
String? date; String? date;
String? siteTransferFrom; String? siteTransferFrom;
String? siteTransferTo; String? siteTransferTo;
int? transactionType; int? transactionType;
int? numberOfAssets;
int? numberOfSites;
RequestsDetails( RequestsDetails(
{this.id, {this.id,
@ -142,6 +145,9 @@ class RequestsDetails {
this.manufacturer, this.manufacturer,
this.requestType, this.requestType,
this.requestNo, this.requestNo,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.gasType, this.gasType,
this.site, this.site,
this.statusReceiver, this.statusReceiver,
@ -165,6 +171,9 @@ class RequestsDetails {
supplier = json['supplier']; supplier = json['supplier'];
manufacturer = json['manufacturer']; manufacturer = json['manufacturer'];
requestType = json['requestType']; requestType = json['requestType'];
sessionType = json['sessionType'];
numberOfAssets = json['numberOfAssets'];
numberOfSites = json['numberOfSites'];
requestNo = json['requestNo']; requestNo = json['requestNo'];
gasType = json['gasType']; gasType = json['gasType'];
site = json['site']; site = json['site'];
@ -197,6 +206,9 @@ class RequestsDetails {
data['statusReceiver'] = statusReceiver; data['statusReceiver'] = statusReceiver;
data['assetTransferFrom'] = assetTransferFrom; data['assetTransferFrom'] = assetTransferFrom;
data['assetTransferTo'] = assetTransferTo; data['assetTransferTo'] = assetTransferTo;
data['sessionType'] = sessionType;
data['numberOfSites'] = numberOfSites;
data['numberOfAssets'] = numberOfAssets;
data['code'] = code; data['code'] = code;
data['date'] = date; data['date'] = date;
data['siteTransferFrom'] = siteTransferFrom; data['siteTransferFrom'] = siteTransferFrom;

@ -142,11 +142,11 @@ class Asset {
Building? building; // Now nullable Building? building; // Now nullable
Floor? floor; // Now nullable Floor? floor; // Now nullable
Department? department; // Now nullable Department? department; // Now nullable
Rooms? room;
MappedSite? mappedSite; // Now nullable MappedSite? mappedSite; // Now nullable
MappedBuilding? mappedBuilding; // Now nullable MappedBuilding? mappedBuilding; // Now nullable
MappedFloor? mappedFloor; // Now nullable MappedFloor? mappedFloor; // Now nullable
MappedDepartment? mappedDepartment; // No MappedDepartment? mappedDepartment; //
Rooms? room; // Now nullable
num? testsDay; // Now nullable num? testsDay; // Now nullable
num? purchasingPrice; // Now nullable num? purchasingPrice; // Now nullable
String? nbv; // Now nullable String? nbv; // Now nullable

@ -50,17 +50,34 @@ class Data {
String? priorityName; String? priorityName;
bool? isHighPriority; bool? isHighPriority;
String? assetName; String? assetName;
String? sessionType;
String? rejectReason; String? rejectReason;
String? assetNumber; String? assetNumber;
String? requestTypeName; String? requestTypeName;
String? requestNo; String? requestNo;
int? transactionNo; int? transactionNo;
int? numberOfSites;
int? numberOfAssets;
String? nameOfType; String? nameOfType;
Data({this.id, this.typeTransaction, this.nameOfType,this.transactionDate, this.statusName, this.priorityName, this.isHighPriority, this.assetName, this.assetNumber, this.requestTypeName, this.requestNo,this.transactionNo}); Data(
{this.id,
this.typeTransaction,
this.nameOfType,
this.transactionDate,
this.statusName,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.priorityName,
this.isHighPriority,
this.assetName,
this.assetNumber,
this.requestTypeName,
this.requestNo,
this.transactionNo});
Data.fromJson(Map<String, dynamic> json) { Data.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
typeTransaction = json['typeTransaction']; typeTransaction = json['typeTransaction'];
transactionDate = json['transactionDate']; transactionDate = json['transactionDate'];
@ -68,6 +85,9 @@ class Data {
priorityName = json['priorityName']; priorityName = json['priorityName'];
isHighPriority = json['isHighPriority']; isHighPriority = json['isHighPriority'];
assetName = json['assetName']; assetName = json['assetName'];
sessionType = json['sessionType'];
numberOfSites = json['numberOfSites'];
numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber']; assetNumber = json['assetNumber'];
requestTypeName = json['requestTypeName']; requestTypeName = json['requestTypeName'];
requestNo = json['requestNo']; requestNo = json['requestNo'];
@ -90,6 +110,9 @@ class Data {
data['requestNo'] = requestNo; data['requestNo'] = requestNo;
data['rejectReason'] = rejectReason; data['rejectReason'] = rejectReason;
data['transactionNo'] = transactionNo; data['transactionNo'] = transactionNo;
data['sessionType'] = sessionType;
data['numberOfAssets'] = numberOfAssets;
data['numberOfSites'] = numberOfSites;
data['nameOfType'] = nameOfType; data['nameOfType'] = nameOfType;
return data; return data;
} }

@ -1,3 +1,12 @@
import 'dart:developer';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/service_request/supplier_details.dart';
import '../../../models/new_models/department.dart';
class AssetInventoryResponse { class AssetInventoryResponse {
num? totalRows; num? totalRows;
num? count; num? count;
@ -28,9 +37,7 @@ class AssetInventoryResponse {
responseCode = json['responseCode']; responseCode = json['responseCode'];
isSuccess = json['isSuccess']; isSuccess = json['isSuccess'];
if (json['data'] != null) { if (json['data'] != null) {
assetList = (json['data'] as List) assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList();
.map((item) => AssetInventoryModel.fromJson(item))
.toList();
} }
} }
@ -43,7 +50,6 @@ class AssetInventoryResponse {
'innerMessage': innerMessage, 'innerMessage': innerMessage,
'responseCode': responseCode, 'responseCode': responseCode,
'isSuccess': isSuccess, 'isSuccess': isSuccess,
// assetList not needed in toJson because youll likely only send AssetInventoryModel for updates
}; };
} }
} }
@ -54,68 +60,69 @@ class AssetInventoryModel {
String? assetNumber; String? assetNumber;
String? serialNo; String? serialNo;
String? assetName; String? assetName;
num? assetNameId;
String? model; String? model;
String? manufacturer; String? manufacturer;
String? supplierName; String? supplierName;
String? site; String? siteName;
String? building; String? buildingName;
String? floor; String? floorName;
String? department; String? departmentName;
String? room; String? roomName;
num? statusId; num? statusId;
String? status; String? status;
num? statusValue; num? statusValue;
num? statusByAdminId; num? statusByAdminId;
String? statusByAdmin; String? statusByAdmin;
num? statusByAdminValue; num? statusByAdminValue;
bool? isNotRegistered; bool? isNotRegistered;
num? sessionId; num? sessionId;
num? assetImportId; num? assetImportId;
num? siteId; num? siteId;
num? supplierId;
num? buildingId; num? buildingId;
num? floorId; num? floorId;
num? departmentId; num? departmentId;
num? roomId; num? roomId;
String? oldAssetNumber;
String? newAssetNumber; String? newAssetNumber;
String? oldSerialNo;
String? newSerialNo; String? newSerialNo;
num? oldAssetNameId;
num? newAssetNameId; num? newAssetNameId;
String? newAssetNameText; String? newAssetNameText;
num? oldModelId;
num? newModelId; num? newModelId;
String? newModelName; String? newModelName;
num? oldManufacturerId; num? manufacturerId;
num? modelId;
num? newManufacturerId; num? newManufacturerId;
String? newManufacturerName; String? newManufacturerName;
num? oldSupplierId;
num? newSupplierId; num? newSupplierId;
String? newSupplierName; String? newSupplierName;
String? photo; String? photo;
String? photoOriginName; String? photoOriginName;
String? remarks; String? remarks;
num? oldSiteId;
num? oldBuildingId; Site? site;
num? oldFloorId; Building? building;
num? oldDepartmentId; Floor? floor;
num? oldRoomId; Department? department;
Rooms? room;
SupplierDetails? supplier;
AssetInventoryModel({ AssetInventoryModel({
this.id, this.id,
this.sessionId,
this.assetId, this.assetId,
this.assetNumber, this.assetNumber,
this.assetNameId,
this.serialNo, this.serialNo,
this.assetName, this.assetName,
this.model, this.model,
this.manufacturer, this.manufacturer,
this.supplierName, this.supplierName,
this.site, this.siteName,
this.building, this.buildingName,
this.floor, this.floorName,
this.department, this.departmentName,
this.room, this.roomName,
this.statusId, this.statusId,
this.status, this.status,
this.statusValue, this.statusValue,
@ -123,92 +130,79 @@ class AssetInventoryModel {
this.statusByAdmin, this.statusByAdmin,
this.statusByAdminValue, this.statusByAdminValue,
this.isNotRegistered, this.isNotRegistered,
this.sessionId,
this.assetImportId, this.assetImportId,
this.siteId, this.siteId,
this.buildingId, this.buildingId,
this.floorId, this.floorId,
this.departmentId, this.departmentId,
this.supplierId,
this.roomId, this.roomId,
this.oldAssetNumber,
this.newAssetNumber, this.newAssetNumber,
this.oldSerialNo, this.manufacturerId,
this.newSerialNo, this.newSerialNo,
this.oldAssetNameId,
this.newAssetNameId, this.newAssetNameId,
this.newAssetNameText, this.newAssetNameText,
this.oldModelId,
this.newModelId, this.newModelId,
this.modelId,
this.newModelName, this.newModelName,
this.oldManufacturerId,
this.newManufacturerId, this.newManufacturerId,
this.newManufacturerName, this.newManufacturerName,
this.oldSupplierId,
this.newSupplierId, this.newSupplierId,
this.newSupplierName, this.newSupplierName,
this.photo, this.photo,
this.photoOriginName, this.photoOriginName,
this.remarks, this.remarks,
this.oldSiteId, this.site,
this.oldBuildingId, this.department,
this.oldFloorId, this.building,
this.oldDepartmentId, this.floor,
this.oldRoomId, this.room,
this.supplier,
}); });
AssetInventoryModel.fromJson(Map<String, dynamic> json) { AssetInventoryModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
assetId = json['assetId']; assetId = json['assetId'];
assetNumber = json['assetNumber']; assetNumber = json['assetNumber'];
assetNameId = json['assetNameId'];
serialNo = json['serialNo']; serialNo = json['serialNo'];
assetName = json['assetName']; assetName = json['assetName'];
model = json['model']; model = json['model'] ?? json['modelName'];
manufacturer = json['manufacturer']; manufacturer = json['manufacturer'] ?? json['manufacturerName'];
supplierName = json['supplierName']; supplierName = json['supplierName'];
site = json['site']; siteName = json['site'] ?? json['siteName'];
building = json['building']; buildingName = json['building'] ?? json['buildingName'];
floor = json['floor']; floorName = json['floor'] ?? json['floorName'];
department = json['department']; departmentName = json['department'] ?? json['departmentName'];
room = json['room']; roomName = json['room'] ?? json['roomName'];
statusId = json['statusId']; statusId = json['statusId'];
status = json['status']; status = json['status'] ?? json['classification'];
statusValue = json['statusValue']; statusValue = json['statusValue'];
statusByAdminId = json['statusByAdminId'];
statusByAdmin = json['statusByAdmin'];
statusByAdminValue = json['statusByAdminValue'];
isNotRegistered = json['isNotRegistered']; isNotRegistered = json['isNotRegistered'];
sessionId = json['sessionId']; sessionId = json['sessionId'];
assetImportId = json['assetImportId']; assetImportId = json['assetImportId']??json['id'];
siteId = json['siteId']; siteId = json['siteId'];
buildingId = json['buildingId']; buildingId = json['buildingId'];
floorId = json['floorId']; floorId = json['floorId'];
supplierId = json['supplierId'];
departmentId = json['departmentId']; departmentId = json['departmentId'];
roomId = json['roomId']; roomId = json['roomId'];
oldAssetNumber = json['oldAssetNumber']; modelId = json['modelId'];
newAssetNumber = json['newAssetNumber'];
oldSerialNo = json['oldSerialNo'];
newSerialNo = json['newSerialNo'];
oldAssetNameId = json['oldAssetNameId'];
newAssetNameId = json['newAssetNameId'];
newAssetNameText = json['newAssetNameText'];
oldModelId = json['oldModelId'];
newModelId = json['newModelId'];
newModelName = json['newModelName'];
oldManufacturerId = json['oldManufacturerId'];
newManufacturerId = json['newManufacturerId'];
newManufacturerName = json['newManufacturerName'];
oldSupplierId = json['oldSupplierId'];
newSupplierId = json['newSupplierId'];
newSupplierName = json['newSupplierName'];
photo = json['photo']; photo = json['photo'];
photoOriginName = json['photoOriginName']; photoOriginName = json['photoOriginName'];
remarks = json['remarks']; remarks = json['remarks'];
oldSiteId = json['oldSiteId']; //new data..
oldBuildingId = json['oldBuildingId']; // newAssetNumber = json['newAssetNumber'] ?? json['assetNumber'];
oldFloorId = json['oldFloorId']; // manufacturerId = json['manufacturerId'] ?? json['manufacturerId'];
oldDepartmentId = json['oldDepartmentId']; // newSerialNo = json['newSerialNo'] ?? json['serialNo'];
oldRoomId = json['oldRoomId']; // newAssetNameId = json['newAssetNameId'] ?? json['assetNameId'];
// newAssetNameText = json['newAssetNameText'] ?? json['assetNameText'];
// newModelId = json['newModelId'] ?? json['modelId'];
// newModelName = json['newModelName'] ?? json['modelName'];
// newManufacturerId = json['newManufacturerId'] ?? json['manufacturerId'];
// newManufacturerName = json['newManufacturerName'] ?? json['manufacturerName'];
// newSupplierId = json['newSupplierId'] ?? json['supplierId'];
// newSupplierName = json['newSupplierName'] ?? json['supplierName'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -222,30 +216,76 @@ class AssetInventoryModel {
'floorId': floorId, 'floorId': floorId,
'departmentId': departmentId, 'departmentId': departmentId,
'roomId': roomId, 'roomId': roomId,
'oldAssetNumber': oldAssetNumber,
'newAssetNumber': newAssetNumber,
'oldSerialNo': oldSerialNo,
'newSerialNo': newSerialNo, 'newSerialNo': newSerialNo,
'oldAssetNameId': oldAssetNameId,
'newAssetNameId': newAssetNameId, 'newAssetNameId': newAssetNameId,
'newAssetNameText': newAssetNameText, 'newAssetNameText': newAssetNameText,
'oldModelId': oldModelId,
'newModelId': newModelId, 'newModelId': newModelId,
'newModelName': newModelName, 'newModelName': newModelName,
'oldManufacturerId': oldManufacturerId,
'newManufacturerId': newManufacturerId, 'newManufacturerId': newManufacturerId,
'newManufacturerName': newManufacturerName, 'newManufacturerName': newManufacturerName,
'oldSupplierId': oldSupplierId,
'newSupplierId': newSupplierId, 'newSupplierId': newSupplierId,
'newSupplierName': newSupplierName, 'newSupplierName': newSupplierName,
'photo': photo, 'photo': photo,
'photoOriginName': photoOriginName,
'remarks': remarks, 'remarks': remarks,
'oldSiteId': oldSiteId,
'oldBuildingId': oldBuildingId,
'oldFloorId': oldFloorId,
'oldDepartmentId': oldDepartmentId,
'oldRoomId': oldRoomId,
}; };
} }
AssetInventoryModel mergeWith(AssetInventoryModel? other) {
if (other == null) return this;
return AssetInventoryModel(
id: id ?? other.id,
assetId: assetId ?? other.assetId,
assetNumber: assetNumber ?? other.assetNumber,
serialNo: serialNo ?? other.serialNo,
assetName: assetName ?? other.assetName,
assetNameId: assetNameId ?? other.assetNameId,
model: model ?? other.model,
manufacturer: manufacturer ?? other.manufacturer,
supplierName: supplierName ?? other.supplierName,
siteName: siteName ?? other.siteName,
buildingName: buildingName ?? other.buildingName,
floorName: floorName ?? other.floorName,
departmentName: departmentName ?? other.departmentName,
roomName: roomName ?? other.roomName,
statusId: statusId ?? other.statusId,
status: status ?? other.status,
statusValue: statusValue ?? other.statusValue,
statusByAdminId: statusByAdminId ?? other.statusByAdminId,
statusByAdmin: statusByAdmin ?? other.statusByAdmin,
statusByAdminValue: statusByAdminValue ?? other.statusByAdminValue,
isNotRegistered: isNotRegistered ?? other.isNotRegistered,
sessionId: sessionId ?? other.sessionId,
assetImportId: assetImportId ?? other.assetImportId,
siteId: siteId ?? other.siteId,
supplierId: supplierId ?? other.supplierId,
buildingId: buildingId ?? other.buildingId,
floorId: floorId ?? other.floorId,
departmentId: departmentId ?? other.departmentId,
roomId: roomId ?? other.roomId,
newAssetNumber: newAssetNumber ?? other.newAssetNumber,
newSerialNo: newSerialNo ?? other.newSerialNo,
newAssetNameId: newAssetNameId ?? other.newAssetNameId,
newAssetNameText: newAssetNameText ?? other.newAssetNameText,
newModelId: newModelId ?? other.newModelId,
newModelName: newModelName ?? other.newModelName,
manufacturerId: manufacturerId ?? other.manufacturerId,
modelId: modelId ?? other.modelId,
newManufacturerId: newManufacturerId ?? other.newManufacturerId,
newManufacturerName: newManufacturerName ?? other.newManufacturerName,
newSupplierId: newSupplierId ?? other.newSupplierId,
newSupplierName: newSupplierName ?? other.newSupplierName,
photo: photo ?? other.photo,
photoOriginName: photoOriginName ?? other.photoOriginName,
remarks: remarks ?? other.remarks,
site: site ?? other.site,
building: building ?? other.building,
floor: floor ?? other.floor,
department: department ?? other.department,
room: room ?? other.room,
supplier: supplier ?? other.supplier,
);
}
} }

@ -5,6 +5,7 @@ class SessionModel {
int? id; int? id;
String? sessionName; String? sessionName;
int? sessionTypeId; int? sessionTypeId;
int? sessionTypeValue;
String? sessionTypeName; String? sessionTypeName;
int? statusId; int? statusId;
String? statusName; String? statusName;
@ -17,6 +18,7 @@ class SessionModel {
this.id, this.id,
this.sessionName, this.sessionName,
this.sessionTypeId, this.sessionTypeId,
this.sessionTypeValue,
this.sessionTypeName, this.sessionTypeName,
this.statusId, this.statusId,
this.statusName, this.statusName,
@ -33,6 +35,7 @@ class SessionModel {
id = json['id']; id = json['id'];
sessionName = json['sessionName']; sessionName = json['sessionName'];
sessionTypeId = json['sessionTypeId']; sessionTypeId = json['sessionTypeId'];
sessionTypeValue = json['sessionTypeValue'];
sessionTypeName = json['sessionTypeName']; sessionTypeName = json['sessionTypeName'];
statusId = json['statusId']; statusId = json['statusId'];
statusName = json['statusName']; statusName = json['statusName'];
@ -53,6 +56,7 @@ class SessionModel {
map['id'] = id; map['id'] = id;
map['sessionName'] = sessionName; map['sessionName'] = sessionName;
map['sessionTypeId'] = sessionTypeId; map['sessionTypeId'] = sessionTypeId;
map['sessionTypeValue'] = sessionTypeValue;
map['sessionTypeName'] = sessionTypeName; map['sessionTypeName'] = sessionTypeName;
map['statusId'] = statusId; map['statusId'] = statusId;
map['statusName'] = statusName; map['statusName'] = statusName;

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
@ -11,10 +13,12 @@ import 'package:test_sa/views/widgets/loaders/image_loader.dart';
class AssetDetailCardView extends StatelessWidget { class AssetDetailCardView extends StatelessWidget {
AssetInventoryModel assetInventoryModel; AssetInventoryModel assetInventoryModel;
VoidCallback onDeletePress;
AssetDetailCardView({ AssetDetailCardView({
super.key, super.key,
required this.assetInventoryModel, required this.assetInventoryModel,
required this.onDeletePress,
}); });
@override @override
@ -30,6 +34,10 @@ class AssetDetailCardView extends StatelessWidget {
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
), ),
// 8.height, // 8.height,
Text(
'${context.translation.assetNumber}: ${assetInventoryModel.assetNumber ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text( Text(
'${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}', '${context.translation.serialNo}: ${assetInventoryModel.serialNo ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
@ -43,11 +51,19 @@ class AssetDetailCardView extends StatelessWidget {
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
Text( Text(
'${context.translation.site}: ${assetInventoryModel.site ?? ''}', '${context.translation.site}: ${assetInventoryModel.siteName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
Text( Text(
'${context.translation.department}: ${assetInventoryModel.department ?? ''}', '${context.translation.building}: ${assetInventoryModel.buildingName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.floor}: ${assetInventoryModel.floorName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.department}: ${assetInventoryModel.departmentName ?? ''}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
), ),
Text( Text(
@ -64,19 +80,9 @@ class AssetDetailCardView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Row( 'delete_icon'.toSvgAsset().onPress(() {
mainAxisAlignment: MainAxisAlignment.spaceBetween, onDeletePress();
crossAxisAlignment: CrossAxisAlignment.start, }),
children: [
'edit_icon'.toSvgAsset().onPress(() {
//Handle edit...
}),
20.width,
'delete_icon'.toSvgAsset().onPress(() {
//handle delete..
})
],
),
20.height, 20.height,
Container( Container(
decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)), decoration: BoxDecoration(color: AppColor.neutral100, borderRadius: BorderRadius.circular(15)),

@ -1,81 +1,82 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:flutter_advanced_switch/flutter_advanced_switch.dart';
import 'package:test_sa/common_widgets/autocomplete_generic_field.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/common_widgets/lookup_autocomplete_field.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
import 'package:test_sa/models/service_request/supplier_details.dart'; import 'package:test_sa/models/service_request/supplier_details.dart';
import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/search_asset_view.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/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/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/app_text_form_field.dart';
import 'package:test_sa/providers/work_order/vendor_provider.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart'; import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../../../new_views/common_widgets/app_filled_button.dart'; import '../../../new_views/common_widgets/app_filled_button.dart';
import '../../../new_views/common_widgets/default_app_bar.dart'; import '../../../new_views/common_widgets/default_app_bar.dart';
import '../../../new_views/common_widgets/single_item_drop_down_menu.dart'; import 'asset_inventory_site_information_view.dart';
class AssetInventoryFormView extends StatefulWidget { class AssetInventoryFormView extends StatefulWidget {
static const String id = "/asset-inventory-form"; static const String id = "/asset-inventory-form";
// TODO need to use only one model AssetInventoryModel everywhere after completing flow . AssetInventoryModel? assetInventoryModel;
Asset ? assetLocation; int? sessionTypeValue;
AssetInventoryFormView({Key? key,this.assetLocation}) : super(key: key); AssetInventoryFormView({Key? key, this.assetInventoryModel, this.sessionTypeValue}) : super(key: key);
@override @override
State<AssetInventoryFormView> createState() => _AssetInventoryFormViewState(); State<AssetInventoryFormView> createState() => _AssetInventoryFormViewState();
} }
class _AssetInventoryFormViewState extends State<AssetInventoryFormView> { class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
final AssetInventoryModel _assetInventoryModel = AssetInventoryModel(); AssetInventoryModel? _scannedAssetModel = AssetInventoryModel();
AssetInventoryModel? _pickedAssetModel = AssetInventoryModel();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Asset? _pickedAsset; final TextEditingController _assetNoController = TextEditingController();
final TextEditingController _serialNoController = TextEditingController();
final TextEditingController _remarksController = TextEditingController();
ValueNotifier<bool>? registeredController;
bool isRegistered = false;
final List<GenericAttachmentModel> attachments = []; // TextEditingController _assetModelController = TextEditingController();
// TextEditingController _assetManufacturerController = TextEditingController();
// TextEditingController _assetSupplierController = TextEditingController();
void _onSubmit() async { final List<GenericAttachmentModel> attachments = [];
_assetInventoryModel.assetId = _pickedAsset?.id;
_assetInventoryModel.oldSiteId = widget.assetLocation?.site?.id;
_assetInventoryModel.oldBuildingId = widget.assetLocation?.building?.id;
_assetInventoryModel.oldFloorId = widget.assetLocation?.floor?.id;
_assetInventoryModel.oldDepartmentId = widget.assetLocation?.department?.id;
_assetInventoryModel.oldRoomId = widget.assetLocation?.room?.id;
if (!_formKey.currentState!.validate() || !(await validateRequest())) { @override
return; void initState() {
} super.initState();
_formKey.currentState!.save();
//TODO need to confirm attachment structure and final api calling .
// List<AssetTransferAttachment> attachement = [];
// for (var item in attachments) {
// String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
// attachement.add(AssetTransferAttachment(id: item.id, attachmentName: fileName));
// }
// _assetInventoryModel.attachments = attachement;
// await _deviceTransferProvider.createRequest(
// context: context,
// model: _transferModel,
// );
// if (_deviceTransferProvider.stateCode == 200) {
// DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
// dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse);
// }
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
resetData();
}
void populateFormValues() {
_serialNoController.text = _scannedAssetModel!.serialNo ?? '';
_assetNoController.text = _scannedAssetModel!.assetNumber ?? '';
// _scannedAssetModel?.supplier = SupplierDetails(
// suppliername: _scannedAssetModel?.supplierName,
// id: _scannedAssetModel?.supplierId,
// );
} }
@override @override
@ -94,147 +95,206 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
AssetPicker( if (widget.sessionTypeValue == 1 || widget.sessionTypeValue == 2) ...[
device: _pickedAsset, Row(
showLoading: false, mainAxisAlignment: MainAxisAlignment.spaceBetween,
labelColor: AppColor.white936, children: [
iconColor: AppColor.neutral120, 'Not Registered'.addTranslation.heading5(context),
label: 'Scan Asset'.addTranslation, AdvancedSwitch(
borderColor: AppColor.white936, controller: registeredController,
buttonColor: Colors.white, activeColor: AppColor.green50.withOpacity(0.5),
showBorder: true, inactiveColor: AppColor.neutral10,
onPick: (asset) async { thumb: CircleAvatar(backgroundColor: isRegistered == true ? AppColor.green50 : AppColor.neutral20),
_pickedAsset = asset; borderRadius: const BorderRadius.all(Radius.circular(30)),
//TODO set value to model . width: 42.toScreenWidth,
// if (_pickedAsset?.site != null && _transferModel.transferType?.value == 1) { height: 24.toScreenHeight,
// await _deviceTransferProvider.getSiteData(siteId: int.tryParse(_pickedAsset!.site!.id.toString())); onChanged: (value) {
// _assetDestination.site = _deviceTransferProvider.internalAssetDestination?.site; isRegistered = value;
// _assetDestination.building = null; resetData();
// _assetDestination.floor = null; setState(() {});
// _assetDestination.department = null; },
// } else if (_pickedAsset?.site != null && _transferModel.transferType?.value == 2) { disabledOpacity: 1,
// _assetDestination.site = null; ),
// _assetDestination.building = null; ],
// _assetDestination.floor = null; ),
// _assetDestination.department = null; 16.height,
// } ],
if ((!isRegistered && widget.sessionTypeValue == 1) || (widget.sessionTypeValue == 3) || (!isRegistered && widget.sessionTypeValue == 2)) ...[
AssetPicker(
showLoading: false,
labelColor: AppColor.white936,
iconColor: AppColor.neutral120,
label: 'Scan Asset'.addTranslation,
borderColor: AppColor.white936,
buttonColor: Colors.white,
enablePickManually: false,
showAssetInfo: false,
showBorder: true,
onPick: (asset) async {
resetData();
setState(() {});
if (asset.assetNumber != null) {
searchAsset(assetNo: asset.assetNumber!);
}
}),
12.height,
AppTextFormField(
labelText: context.translation.assetNo,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
controller: _assetNoController,
showShadow: false,
enable: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
),
12.height,
],
if (((!isRegistered && widget.sessionTypeValue == 2)))
AppFilledButton(
label: 'Search Asset'.addTranslation,
onPressed: () async {
resetData(isScanned: false);
setState(() {}); setState(() {});
}), await Navigator.push(
12.height, context,
AppTextFormField( MaterialPageRoute(
labelText: context.translation.assetNo, builder: (context) => SearchAssetView(
backgroundColor: AppColor.fieldBgColor(context), sessionId: widget.assetInventoryModel?.sessionId ?? 0,
textAlign: TextAlign.center, ))).then((value) {
showShadow: false, if (value != null) {
labelStyle: AppTextStyles.textFieldLabelStyle, _pickedAssetModel = value;
style: Theme.of(context).textTheme.titleMedium, // _pickedAssetModel?.assetNumber = _scannedAssetModel?.assetNumber;
), // _pickedAssetModel?.assetId = _scannedAssetModel?.assetId;
12.height, // _pickedAssetModel?.status = _scannedAssetModel?.status;
_scannedAssetModel = _scannedAssetModel?.mergeWith(_pickedAssetModel) ?? _pickedAssetModel;
populateFormValues();
setState(() {});
}
///Need to assign the values
});
},
).paddingOnly(bottom: 12),
AppTextFormField( AppTextFormField(
labelText: context.translation.serialNo, labelText: context.translation.serialNo,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
controller: _serialNoController,
textAlign: TextAlign.center, textAlign: TextAlign.center,
showShadow: false, showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle, labelStyle: AppTextStyles.textFieldLabelStyle,
onChange: (value) {
if (value != _scannedAssetModel?.serialNo) {
_scannedAssetModel?.newSerialNo = value;
// setState(() {});
}
},
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
12.height, 12.height,
AutoCompleteGenericField<SparePartsWorkOrders>( LookUpAutoCompleteField(
clearAfterPick: false, clearAfterPick: false,
label: 'Asset Name'.addTranslation, forAssetName: true,
displayString: (item) => "", onChanged: (value) {
onSearch: (query) async { _scannedAssetModel?.newAssetNameId = null;
// final provider = Provider.of<PartsProvider>(context, listen: false); _scannedAssetModel?.newAssetNameText = value;
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
}, },
initialValue: '', initialValue: _scannedAssetModel?.assetName ?? "",
// initialValue: model.partCatalogItem?.partNumber ?? "", label: 'Asset Name'.addTranslation,
onPick: (part) { onPick: (value) {
_scannedAssetModel?.newAssetNameText = null;
_scannedAssetModel?.assetName = value.name;
_scannedAssetModel?.newAssetNameId = value.id;
setState(() {}); setState(() {});
}, },
), ),
12.height, 12.height,
//Asset Name.. //Asset Name..
AutoCompleteGenericField<SparePartsWorkOrders>( LookUpAutoCompleteField(
clearAfterPick: false, clearAfterPick: false,
isManufacturer: true,
initialValue: _scannedAssetModel?.manufacturer ?? "",
label: 'Manufacturer'.addTranslation, label: 'Manufacturer'.addTranslation,
displayString: (item) => "", onChanged: (value) {
onSearch: (query) async { _scannedAssetModel?.newManufacturerId = null;
// final provider = Provider.of<PartsProvider>(context, listen: false); _scannedAssetModel?.newManufacturerName = value;
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
}, },
initialValue: '', onPick: (value) {
// initialValue: model.partCatalogItem?.partNumber ?? "", _scannedAssetModel?.newManufacturerName = null;
onPick: (part) { _scannedAssetModel?.manufacturer = value.name;
_scannedAssetModel?.newManufacturerId = value.id;
setState(() {}); setState(() {});
}, },
), ),
12.height, 12.height,
//manufacture.. LookUpAutoCompleteField(
AutoCompleteGenericField<SparePartsWorkOrders>(
clearAfterPick: false, clearAfterPick: false,
isManufacturer: false,
initialValue: _scannedAssetModel?.model ?? "",
label: 'Model'.addTranslation, label: 'Model'.addTranslation,
displayString: (item) => "", onChanged: (value) {
onSearch: (query) async { _scannedAssetModel?.newModelId = null;
// final provider = Provider.of<PartsProvider>(context, listen: false); _scannedAssetModel?.newModelName = value;
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
}, },
initialValue: '', onPick: (value) {
// initialValue: model.partCatalogItem?.partNumber ?? "", _scannedAssetModel?.newModelName = null;
onPick: (part) { _scannedAssetModel?.model = value.name;
_scannedAssetModel?.newModelId = value.id;
setState(() {}); setState(() {});
}, },
), ),
12.height, 12.height,
//model..
AutoCompleteGenericField<SparePartsWorkOrders>( LookUpAutoCompleteField(
clearAfterPick: false, clearAfterPick: false,
label: 'Asset Name'.addTranslation, forSupplier: true,
displayString: (item) => "", initialValue: _scannedAssetModel?.supplierName ?? "",
onSearch: (query) async { label: context.translation.supplier,
// final provider = Provider.of<PartsProvider>(context, listen: false); onChanged: (value) {
// final list = await provider.getPartsList(partName: query); _scannedAssetModel?.newSupplierId = null;
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList(); _scannedAssetModel?.newSupplierName = value;
return [];
}, },
initialValue: '', onPick: (value) {
// initialValue: model.partCatalogItem?.partNumber ?? "", _scannedAssetModel?.newSupplierName = null;
onPick: (part) { _scannedAssetModel?.supplierName = value.name;
_scannedAssetModel?.newSupplierId = value.id;
setState(() {}); setState(() {});
}, },
), ),
// SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
// context: context,
// title: context.translation.supplier,
// backgroundColor: AppColor.fieldBgColor(context),
// initialValue: _scannedAssetModel?.supplier,
// showAsBottomSheet: true,
// showShadow: false,
// showCancel: true,
// onSelect: (supplier) {
// _scannedAssetModel?.supplier = supplier;
// _scannedAssetModel?.newSupplierId = supplier?.id;
// _scannedAssetModel?.newSupplierName = supplier?.name;
// setState(() {});
// },
// ),
12.height, 12.height,
SingleItemDropDownMenu<SupplierDetails, VendorProvider>( siteInfoContainer(label: context.translation.site, value: _scannedAssetModel?.siteName ?? '-'),
context: context,
title: context.translation.supplier,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: null,
showAsBottomSheet: true,
showShadow: false,
showCancel: true,
onSelect: (supplier) {
setState(() {});
},
),
12.height,
siteInfoContainer(label: context.translation.site, value:widget.assetLocation?.site?.name??'-' ),
12.height, 12.height,
siteInfoContainer(label: context.translation.building, value:widget.assetLocation?.building?.name??'-' ), siteInfoContainer(label: context.translation.building, value: _scannedAssetModel?.buildingName ?? '-'),
12.height, 12.height,
siteInfoContainer(label: context.translation.floor, value:widget.assetLocation?.floor?.name??'-' ), siteInfoContainer(label: context.translation.floor, value: _scannedAssetModel?.floorName ?? '-'),
12.height, 12.height,
siteInfoContainer(label: context.translation.department, value:widget.assetLocation?.department?.name??'-' ), siteInfoContainer(label: context.translation.department, value: _scannedAssetModel?.departmentName ?? '-'),
12.height, 12.height,
siteInfoContainer(label: context.translation.room, value:widget.assetLocation?.room?.name??'-' ), siteInfoContainer(label: context.translation.room, value: _scannedAssetModel?.roomName ?? '-'),
12.height, 12.height,
classificationWidget(label: 'Found'), if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) classificationWidget(label: _scannedAssetModel?.status),
12.height, 12.height,
Text( Text(
'Asset Photo'.addTranslation, 'Asset Photo'.addTranslation,
@ -269,8 +329,10 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
alignLabelWithHint: true, alignLabelWithHint: true,
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
showShadow: false, showShadow: false,
controller: _remarksController,
onSaved: (text) { onSaved: (text) {
_assetInventoryModel.remarks = text; _scannedAssetModel?.remarks = text;
setState(() {});
}, },
), ),
// 100.height, // 100.height,
@ -288,21 +350,41 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
); );
} }
Future<void> searchAsset({required String assetNo}) async {
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"assetNumber": assetNo,
"sessionId": widget.assetInventoryModel?.sessionId,
"siteId": widget.assetInventoryModel?.site?.id,
"buildingId": widget.assetInventoryModel?.building?.id,
"floorId": widget.assetInventoryModel?.floor?.id,
"departmentId": widget.assetInventoryModel?.department?.id,
"roomId": widget.assetInventoryModel?.room?.id,
};
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
_scannedAssetModel = await provider.searchAsset(payload: payload);
Navigator.pop(context);
if (_scannedAssetModel != null) {
populateFormValues();
}
setState(() {});
}
Widget siteInfoContainer({required String label , required String value}){ Widget siteInfoContainer({required String label, required String value}) {
//TODO may be need to hide value for if empty or null . //TODO may be need to hide value for if empty or null .
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth,vertical: 12.toScreenHeight), padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight),
decoration: BoxDecoration( decoration: BoxDecoration(color: AppColor.neutral80, borderRadius: BorderRadius.circular(8)),
color: AppColor.neutral80,
borderRadius: BorderRadius.circular(8)
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(label,style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)), Text(label, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500)),
Text(value,style:Theme.of(context).textTheme.bodyLarge,), Text(
value,
style: Theme.of(context).textTheme.bodyLarge,
),
], ],
), ),
); );
@ -327,27 +409,53 @@ class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
); );
} }
Future<bool> validateRequest() async { void _onSubmit() async {
if (_pickedAsset == null) { AssetInventoryProvider assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
await Fluttertoast.showToast(msg: "Please Select Asset"); _formKey.currentState!.save();
return false; _scannedAssetModel?.sessionId = widget.assetInventoryModel?.sessionId;
_scannedAssetModel?.siteId = widget.assetInventoryModel?.site?.id;
_scannedAssetModel?.buildingId = widget.assetInventoryModel?.building?.id;
_scannedAssetModel?.floorId = widget.assetInventoryModel?.floor?.id;
_scannedAssetModel?.departmentId = widget.assetInventoryModel?.department?.id;
_scannedAssetModel?.roomId = widget.assetInventoryModel?.room?.id;
_scannedAssetModel?.isNotRegistered = isRegistered;
if (attachments.isNotEmpty) {
String? photoName = attachments.first.name;
String fileName = ServiceRequestUtils.isLocalUrl(photoName ?? '') ? ("${photoName ?? ''.split("/").last}|${base64Encode(File(photoName ?? '').readAsBytesSync())}") : photoName ?? '';
_scannedAssetModel?.photo = fileName;
}
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
assetInventoryProvider.saveAssetInSession(model: _scannedAssetModel).then((success) {
///Need to use push and remove until...
Navigator.pop(context);
if (success) {
// Navigator.pop(context);
// Navigator.pop(context);
/// need to confirm need to call this ...
AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
allRequestsProvider.reset();
allRequestsProvider.getAllRequests(context, typeTransaction: 8);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (contxt) => SiteInformationView(
sessionModel: SessionModel(id: int.tryParse(widget.assetInventoryModel?.sessionId?.toString() ?? '') ?? 0),
)));
} else {
log('api error...');
}
});
}
void resetData({bool isScanned = true}) {
if (isScanned) {
_scannedAssetModel = AssetInventoryModel();
} }
// if (_assetDestination.site == null) { _assetNoController.clear();
// await Fluttertoast.showToast(msg: "Please Select Site"); _serialNoController.clear();
// return false; _pickedAssetModel = AssetInventoryModel();
// } attachments.clear();
// if (_assetDestination.building == null) { _remarksController.clear();
// await Fluttertoast.showToast(msg: "Please Select Building"); registeredController?.dispose();
// return false;
// }
// if (_assetDestination.floor == null) {
// await Fluttertoast.showToast(msg: "Please Select Floor");
// return false;
// }
// if (_assetDestination.department == null) {
// await Fluttertoast.showToast(msg: "Please Select Department");
// return false;
// }
return true;
} }
} }

@ -10,7 +10,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart'; import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/pick_site_information_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_site_information_view.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.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/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_filled_button.dart';
@ -121,6 +121,7 @@ class _AssetInventoryPageState extends State<AssetInventoryPage> {
} }
Future<void> _scanAsset({required AssetInventoryProvider provider}) async { Future<void> _scanAsset({required AssetInventoryProvider provider}) async {
Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: provider.sessionModel ?? SessionModel()))); provider.siteFilterAssetList.clear();
Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationView(sessionModel: provider.sessionModel ?? SessionModel())));
} }
} }

@ -1,77 +1,131 @@
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.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/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'asset_detail_card_view.dart'; import 'asset_detail_card_view.dart';
class AssetInventoryScanAssetView extends StatefulWidget { class AssetInventoryScanAssetView extends StatefulWidget {
int sessionId ; int sessionId;
AssetInventoryScanAssetView({Key? key,required this.sessionId}) : super(key: key);
AssetInventoryScanAssetView({Key? key, required this.sessionId}) : super(key: key);
@override @override
State<AssetInventoryScanAssetView> createState() => _AssetInventoryScanAssetViewState(); State<AssetInventoryScanAssetView> createState() => _AssetInventoryScanAssetViewState();
} }
class _AssetInventoryScanAssetViewState extends State<AssetInventoryScanAssetView> { class _AssetInventoryScanAssetViewState extends State<AssetInventoryScanAssetView> {
late AssetInventoryProvider assetInventoryProvider; late AssetInventoryProvider assetInventoryProvider;
@override @override
void initState() { void initState() {
assetInventoryProvider = Provider.of<AssetInventoryProvider>(context,listen:false); assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
super.initState(); super.initState();
} }
Future<void> getAssetList({bool reset = false}) async {
if (reset) { Future<void> getAssetList({bool loadMore = false}) async {
assetInventoryProvider.pageNo = 1;
assetInventoryProvider.assetInventoryResponse = null;
}
await assetInventoryProvider.getAssetsInSession( await assetInventoryProvider.getAssetsInSession(
sessionId: widget.sessionId, sessionId: widget.sessionId,
loadMore: loadMore,
); );
} }
@override
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<AssetInventoryProvider>( return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) { builder: (context, provider, _) {
if (provider.isLoading && provider.assetInventoryResponse == null) { if (provider.isLoading && provider.assetInventoryResponse == null) {
//TODO need use existing loader if found..
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
final assets = provider.assetInventoryResponse?.assetList ?? []; final assets = provider.assetInventoryResponse?.assetList ?? [];
if (assets.isEmpty) { if (assets.isEmpty) {
return const Center(child: NoDataFound()); return const Center(child: NoDataFound());
} }
return LazyLoading( return NotificationListener<ScrollNotification>(
nextPage: provider.nextPage, onNotification: (scrollInfo) {
onLazyLoad: () async { if (!provider.isNextPageLoading &&
await getAssetList(); provider.nextPage &&
scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
getAssetList(loadMore: true);
}
return false;
}, },
child: ListView.separated( child: ListView.separated(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
itemCount: assets.length + (provider.isNextPageLoading ? 1 : 0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return AssetDetailCardView(assetInventoryModel: assets[index]); if (index == assets.length) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(child: CircularProgressIndicator()),
);
}
return AssetDetailCardView(
assetInventoryModel: assets[index],
onDeletePress: () async {
await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
if (success) {
await provider.getAssetsInSession(sessionId: widget.sessionId);
}
});
},
);
}, },
separatorBuilder: (context, index) => 12.height, separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
), ),
); );
}, },
); );
} }
void _addAsset(BuildContext context) { // Widget build(BuildContext context) {
//TODO need to confirm navigation... // return Consumer<AssetInventoryProvider>(
Navigator.push(context, MaterialPageRoute(builder: (contxt) => AssetInventoryFormView())); // builder: (context, provider, _) {
} // if (provider.isLoading && provider.assetInventoryResponse == null) {
// //TODO need use existing loader if found..
// return const Center(child: CircularProgressIndicator());
// }
// final assets = provider.assetInventoryResponse?.assetList ?? [];
// if (assets.isEmpty) {
// return const Center(child: NoDataFound());
// }
// return LazyLoading(
// nextPage: provider.nextPage,
// onLazyLoad: () async {
// log('Loading next page...');
// await getAssetList(loadMore: true);
// },
// child: ListView.separated(
// padding: const EdgeInsets.all(16),
// itemBuilder: (context, index) {
// if (index == assets.length) {
// // bottom loader
// return const Padding(
// padding: EdgeInsets.symmetric(vertical: 16),
// child: Center(child: CircularProgressIndicator()),
// );
// }
// return AssetDetailCardView(
// assetInventoryModel: assets[index],
// onDeletePress: () async {
// await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
// if (success) {
// await provider.getAssetsInSession(sessionId: widget.sessionId);
// }
// });
// },
// );
// },
// separatorBuilder: (context, index) => 12.height,
// itemCount: assets.length + (provider.nextPage ? 1 : 0),
// ),
// );
// },
// );
// }
} }

@ -0,0 +1,311 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_detail_card_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
class SiteInformationView extends StatefulWidget {
SessionModel sessionModel;
SiteInformationView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<SiteInformationView> createState() => _SiteInformationViewState();
}
class _SiteInformationViewState extends State<SiteInformationView> {
AssetInventoryModel assetInventoryModel = AssetInventoryModel();
bool showMarkAsComplete = false;
@override
void initState() {
super.initState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: 'Inventory Session Request'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
body: SafeArea(
child: Column(
children: [
ListView(
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
children: [
siteInfoCard(context, widget.sessionModel),
12.height,
assetDetailList(),
8.height,
],
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Add Asset'.addTranslation,
onPressed: () => _addAsset(),
// buttonColor: AppColor.primary10,
),
),
if (showMarkAsComplete)
AppFilledButton(
buttonColor: AppColor.green70,
label: 'Mark as completed'.addTranslation,
onPressed: () => _markAsCompleted(),
// buttonColor: AppColor.primary10,
).paddingOnly(start: 16, end: 16),
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// buttonColor: AppColor.green70,
// label: 'Mark as completed'.addTranslation,
// onPressed: () => _markAsCompleted(),
// // buttonColor: AppColor.primary10,
// ),
// ),
],
),
));
}
void _addAsset() async {
if (await validateRequest()) {
assetInventoryModel.sessionId = widget.sessionModel.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (contxt) => AssetInventoryFormView(
assetInventoryModel: assetInventoryModel,
sessionTypeValue: widget.sessionModel.sessionTypeValue,
)));
}
}
void _markAsCompleted() async {
if (await validateRequest()) {
assetInventoryModel.sessionId = widget.sessionModel.id;
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"sessionId": widget.sessionModel.id,
"siteId": assetInventoryModel.site?.id,
"buildingId": assetInventoryModel.building?.id,
"floorId": assetInventoryModel.floor?.id,
"departmentId": assetInventoryModel.department?.id,
"roomId": assetInventoryModel.room?.id,
};
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await provider.markAsComplete(payload: payload).then((success) {
Navigator.pop(context);
log('success $success');
if (success) {
///TODO need to confirm need to call this or not ..
// AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
// allRequestsProvider.reset();
// allRequestsProvider.getAllRequests(context, typeTransaction: 8);
///Need to call push and remove until...
Navigator.pop(context);
Navigator.pop(context);
}
});
}
}
Widget assetDetailList() {
return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) {
if (provider.isLoading) {
return SizedBox(height: 300.toScreenHeight, child: const CircularProgressIndicator(color: AppColor.primary10).center);
}
final assets = provider.siteFilterAssetList;
return NotificationListener<ScrollNotification>(
onNotification: (scrollInfo) {
if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
getAssetFilteredList(loadMore: true);
}
return false;
},
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return AssetDetailCardView(
assetInventoryModel: assets[index],
onDeletePress: () async {
log('Delete icon press');
await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
if (success) {
await getAssetFilteredList();
await provider.getAssetsInSession(
sessionId: widget.sessionModel.id ?? 0,
);
}
});
},
);
},
separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
),
);
},
);
}
Widget siteInfoCard(BuildContext context, SessionModel sessionModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
SingleItemDropDownMenu<Site, NullableLoadingProvider>(
context: context,
title: context.translation.site,
initialValue: assetInventoryModel.site,
showShadow: false,
staticData: sessionModel.assetInventorySites,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
assetInventoryModel.site = value;
assetInventoryModel.building = null;
assetInventoryModel.floor = null;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: assetInventoryModel.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.site?.buildings?.isNotEmpty ?? false,
staticData: assetInventoryModel.site?.buildings ?? [],
onSelect: (value) {
assetInventoryModel.building = value;
assetInventoryModel.floor = null;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.building?.floors?.isNotEmpty ?? false,
staticData: assetInventoryModel.building?.floors ?? [],
onSelect: (value) {
assetInventoryModel.floor = value;
assetInventoryModel.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.floor?.departments?.isNotEmpty ?? false,
staticData: assetInventoryModel.floor?.departments ?? [],
onSelect: (value) {
assetInventoryModel.department = value;
assetInventoryModel.room = null;
showMarkAsComplete = true;
setState(() {});
getAssetFilteredList();
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetInventoryModel.room,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetInventoryModel.department?.rooms?.isNotEmpty ?? false,
staticData: assetInventoryModel.department?.rooms ?? [],
onSelect: (value) {
assetInventoryModel.room = value;
setState(() {});
if (assetInventoryModel.room != null) {
getAssetFilteredList();
}
},
),
8.height,
],
).toShadowContainer(context);
}
Future<bool> validateRequest() async {
if (assetInventoryModel.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (assetInventoryModel.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (assetInventoryModel.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (assetInventoryModel.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
Future<void> getAssetFilteredList({bool loadMore = false}) async {
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"sessionId": widget.sessionModel.id,
"siteId": assetInventoryModel.site?.id,
"buildingId": assetInventoryModel.building?.id,
"floorId": assetInventoryModel.floor?.id,
"departmentId": assetInventoryModel.department?.id,
"roomId": assetInventoryModel.room?.id,
};
await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore);
}
}

@ -47,10 +47,9 @@ class InventorySessionCard extends StatelessWidget {
), ),
8.height, 8.height,
(requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context), (requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context),
//TODO replace with Api Data.. infoWidget(label: 'Type'.addTranslation, value: requestData?.sessionType, context: context),
infoWidget(label: 'Type'.addTranslation, value: requestData?.requestNo, context: context), infoWidget(label: 'Assets'.addTranslation, value: requestData?.numberOfAssets!=null? requestData?.numberOfAssets.toString():'-', context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestData?.assetName, context: context), infoWidget(label: 'Sites'.addTranslation, value: requestData?.numberOfSites!=null? requestData?.numberOfSites.toString():'-', context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestData?.assetNumber, context: context),
8.height, 8.height,
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -98,11 +97,9 @@ class InventorySessionCard extends StatelessWidget {
), ),
8.height, 8.height,
(requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context), (requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context),
8.height, infoWidget(label: 'Type'.addTranslation, value: requestDetails?.sessionType, context: context),
//TODO replace with Api Data.. infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.numberOfAssets!=null? requestDetails?.numberOfAssets.toString():'-', context: context),
infoWidget(label: 'Type'.addTranslation, value: requestDetails?.requestNo, context: context), infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.numberOfSites!=null? requestDetails?.numberOfSites.toString():'-', context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.assetName, context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.site, context: context),
8.height, 8.height,
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

@ -1,257 +0,0 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_detail_card_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../models/new_models/site.dart';
class PickSiteInformationView extends StatefulWidget {
SessionModel sessionModel;
PickSiteInformationView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<PickSiteInformationView> createState() => _PickSiteInformationViewState();
}
class _PickSiteInformationViewState extends State<PickSiteInformationView> {
// TODO need to use only one model AssetInventoryModel everywhere after completing flow .
Asset assetLocation = Asset();
void _onSave() async {}
@override
void initState() {
super.initState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: 'Inventory Session Request'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
body: Column(
children: [
ListView(
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
children: [
siteInfoCard(context, widget.sessionModel),
12.height,
//TODO need to implement when api is working ...
// assetDetailList(),
// 12.height,
AppFilledButton(
label: "Add Asset".addTranslation,
maxWidth: true,
height: 70,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addAsset,
),
12.height,
],
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.save, maxWidth: true, onPressed: _onSave),
),
],
));
}
void _addAsset() {
Navigator.push(
context,
MaterialPageRoute(
builder: (contxt) => AssetInventoryFormView(
assetLocation: assetLocation,
)));
}
Future<void> getAssetList({bool reset = false}) async {
AssetInventoryProvider assetInventoryProvider = Provider.of<AssetInventoryProvider>(context,listen: false);
if (reset) {
assetInventoryProvider.pageNo = 1;
assetInventoryProvider.assetInventoryResponse = null;
}
await assetInventoryProvider.getAssetsInSession(
sessionId: widget.sessionModel.id??0,
);
}
Widget assetDetailList() {
return Consumer<AssetInventoryProvider>(
builder: (context, provider,child) {
return Consumer<AssetInventoryProvider>(
builder: (context, provider, _) {
if (provider.isLoading && provider.assetInventoryResponse == null) {
//TODO need use existing loader if found..
return const Center(child: CircularProgressIndicator());
}
final assets = provider.assetInventoryResponse?.assetList ?? [];
if (assets.isEmpty) {
return const Center(child: NoDataFound());
}
return LazyLoading(
nextPage: provider.nextPage,
onLazyLoad: () async {
await getAssetList();
},
child: ListView.separated(
padding: const EdgeInsets.all(16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return AssetDetailCardView(assetInventoryModel: assets[index]);
},
separatorBuilder: (context, index) => 12.height,
itemCount: assets.length,
),
);
},
);
}
);
}
Widget siteInfoCard(BuildContext context, SessionModel sessionModel) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
SingleItemDropDownMenu<Site, NullableLoadingProvider>(
context: context,
title: context.translation.site,
initialValue: assetLocation.site,
showShadow: false,
staticData: sessionModel.assetInventorySites,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
assetLocation.site = value;
assetLocation.building = null;
assetLocation.floor = null;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: assetLocation.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.site?.buildings?.isNotEmpty ?? false,
staticData: assetLocation.site?.buildings ?? [],
onSelect: (value) {
assetLocation.building = value;
assetLocation.floor = null;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.building?.floors?.isNotEmpty ?? false,
staticData: assetLocation.building?.floors ?? [],
onSelect: (value) {
assetLocation.floor = value;
assetLocation.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.floor?.departments?.isNotEmpty ?? false,
staticData: assetLocation.floor?.departments ?? [],
onSelect: (value) {
assetLocation.department = value;
assetLocation.room = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
showShadow: false,
showAsBottomSheet: true,
initialValue: assetLocation.room,
backgroundColor: AppColor.fieldBgColor(context),
enabled: assetLocation.department?.rooms?.isNotEmpty ?? false,
staticData: assetLocation.department?.rooms ?? [],
onSelect: (value) {
assetLocation.room = value;
setState(() {});
},
),
8.height,
],
).toShadowContainer(context);
}
Future<bool> validateRequest() async {
if (assetLocation.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (assetLocation.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (assetLocation.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (assetLocation.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
}

@ -0,0 +1,276 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart';
import 'package:test_sa/views/widgets/horizontal_list_widget.dart';
import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import '../../../models/device/asset.dart';
import '../../../models/device/asset_search.dart';
import '../../../new_views/app_style/app_color.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
import '../../../new_views/common_widgets/custom_app_bar.dart';
class SearchAssetView extends StatefulWidget {
static const String id = "asset_search_view";
final num sessionId;
const SearchAssetView({Key? key, required this.sessionId}) : super(key: key);
@override
State<SearchAssetView> createState() => _SearchAssetViewState();
}
class _SearchAssetViewState extends State<SearchAssetView> {
int _selectedIndex = 0;
DeviceSearch? search;
late TextEditingController _searchController;
late AssetInventoryProvider _assetInventoryProvider;
final List<AssetInventoryModel> _searchableList = [];
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _isFirst = true;
@override
void initState() {
_searchController = TextEditingController();
super.initState();
}
@override
void dispose() {
_searchController.dispose();
_assetInventoryProvider.searchReset();
super.dispose();
}
@override
Widget build(BuildContext context) {
List<String> searchBy = [
context.translation.assetName,
context.translation.model,
context.translation.manufacture,
context.translation.snNumber,
context.translation.siteName,
// 'Building Name'.addTranslation,
// 'Floor Name'.addTranslation,
'Department Name'.addTranslation,
///need to check if want to add more filters
];
_assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: CustomAppBar(
title: context.translation.searchAsset,
),
body: Column(
children: [
HorizontalListWidget(
list: searchBy,
callBackFunction: (index) {
setState(() {
_selectedIndex = index;
});
},
).paddingOnly(top: 16, bottom: 0),
Form(
key: _formKey,
child: AppTextFormField(
controller: _searchController,
textInputAction: TextInputAction.search,
labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
onAction: _search,
onChange: (text) {
_searchController.text = text;
_searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
setState(() {});
},
onSaved: (value) {
setState(() {
search = DeviceSearch();
});
_setValue(value);
},
suffixIcon: IconButton(
icon: const Icon(Icons.search),
splashColor: Colors.transparent,
onPressed: _searchController.text.isNotEmpty ? _search : null,
color: AppColor.neutral20,
).paddingOnly(end: 0),
).paddingOnly(top: 16, start: 16, end: 16, bottom: 8),
),
Expanded(
child: _searchableList.isEmpty
? _isFirst
? const SizedBox()
: NoDataFound(message: context.translation.noDeviceFound)
: LazyLoading(
nextPage: _assetInventoryProvider.nextPage,
onLazyLoad: () async {
if (_searchController.text.isNotEmpty) {
await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
setState(() {
_searchableList.clear();
_searchableList.addAll(_assetInventoryProvider.searchDevices);
});
}
},
child: Column(
children: [
ListView.separated(
itemCount: _searchableList.length,
separatorBuilder: (listContext, itemIndex) => 8.height,
padding: const EdgeInsets.all(16),
itemBuilder: (listContext, itemIndex) {
// bool isSelected = selectedAssets.contains(_searchableList[itemIndex].id!);
// String title = isSelected ? "UnSelect" : "Select";
return InventoryAssetItemListView(
device: _searchableList[itemIndex],
// isSelected: isSelected,
onPressed: (device) {
// Navigator.of(context).pop();
Navigator.of(context).pop(device);
},
// selectButton: Text(title, style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context))),
);
},
).expanded,
],
),
),
)
],
));
}
void _search() async {
FocusScope.of(context).unfocus();
_formKey.currentState!.save();
_assetInventoryProvider.searchReset();
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
setState(() {
_searchableList.clear();
_searchableList.addAll(_assetInventoryProvider.searchDevices);
_isFirst = false;
});
Navigator.pop(context);
}
_setValue(value) {
/// todo : check oracle code (no matched parameter)
/// //ontext.translation.assetName,
// context.translation.model,
// context.translation.manufacture,
// context.translation.snNumber,
// context.translation.siteName,
// // 'Building Name'.addTranslation,
// // 'Floor Name'.addTranslation,
// 'Department Name'.addTranslation,
switch (_selectedIndex) {
case 0:
search!.assetName = value;
break;
case 1:
search!.model = value;
break;
case 2:
search!.manufacturer = value;
break;
case 3:
search!.assetSerialNumber = value;
break;
case 4:
search!.site = value;
break;
case 5:
search!.department = value;
break;
default:
break;
}
}
// bool _showResetButton() {
// return (_searchController?.text?.isNotEmpty ?? false);
// }
}
class InventoryAssetItemListView extends StatelessWidget {
final AssetInventoryModel device;
final Function(AssetInventoryModel) onPressed;
final Widget? selectButton;
final bool isSelected;
const InventoryAssetItemListView({Key? key, required this.device, required this.onPressed, this.selectButton, this.isSelected = false}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 95,
height: 95,
decoration: ShapeDecoration(
color: context.isDark ? AppColor.neutral50 : AppColor.neutral30,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(device.photo != null ? URLs.getFileUrl(device.photo!)! : "https://www.lasteelcraft.com/images/no-image-available.png"),
)),
),
15.width,
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
device.assetName!.cleanupWhitespace.capitalizeFirstOfEach.heading6(context),
8.height,
"${context.translation.assetNumber} : ${device.assetNumber}".bodyText(context),
"${context.translation.modelName} : ${device.model}".cleanupWhitespace.capitalizeFirstOfEach.bodyText(context),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
"${context.translation.serialNo} : ${device.serialNo}".bodyText(context).expanded,
4.width,
selectButton ??
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewDetails,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(
Icons.arrow_forward,
color: AppColor.blueStatus(context),
size: 14,
)
],
),
],
)
],
).expanded
],
).toShadowContainer(context, padding: 12, borderColor: isSelected ? AppColor.blueStatus(context) : Colors.transparent).onPress(() => onPressed(device));
}
}

@ -8,6 +8,9 @@ import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/device/asset_search.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart'; import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/service_request/service_request.dart';
@ -26,11 +29,22 @@ import '../../../new_views/common_widgets/app_lazy_loading.dart';
class AssetInventoryProvider extends ChangeNotifier { class AssetInventoryProvider extends ChangeNotifier {
final pageItemNumber = 10; final pageItemNumber = 10;
final searchPageItemNumber = 10;
int pageNo = 1; int pageNo = 1;
List<AssetInventoryModel> _devices = [];
List<AssetInventoryModel> _searchDevices = [];
List<AssetInventoryModel> get devices => _devices;
List<AssetInventoryModel> get searchDevices => _searchDevices;
SessionModel? sessionModel; SessionModel? sessionModel;
//TODO need to check i think don't need to create this obj
AssetInventoryResponse? assetInventoryResponse; AssetInventoryResponse? assetInventoryResponse;
AssetInventoryResponse? siteFilterAssetResponse;
List<AssetInventoryModel> sessionAssetList = []; List<AssetInventoryModel> sessionAssetList = [];
List<AssetInventoryModel> siteFilterAssetList = [];
void reset() { void reset() {
pageNo = 1; pageNo = 1;
@ -42,23 +56,29 @@ class AssetInventoryProvider extends ChangeNotifier {
int? stateCode; int? stateCode;
bool isDetailLoading = false; bool isDetailLoading = false;
bool nextPage = true; bool nextPage = false;
bool isNextPageLoading = false;
bool isLoading = false; bool isLoading = false;
bool isAllAssetLoading = false; bool isAllAssetLoading = false;
Future getSessionById({required int id}) async { void searchReset() {
stateCode = null;
_searchDevices = [];
}
Future<void> getSessionById({required int id}) async {
try { try {
sessionModel = SessionModel(); sessionModel = SessionModel();
isLoading = true; isLoading = true;
notifyListeners(); notifyListeners();
final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id"); final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id");
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]); sessionModel = SessionModel.fromJson(json.decode(response.body)["data"]);
} else { } else {
sessionModel = null; sessionModel = null;
} }
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
@ -72,49 +92,350 @@ class AssetInventoryProvider extends ChangeNotifier {
Future<int> getAssetsInSession({ Future<int> getAssetsInSession({
required int sessionId, required int sessionId,
bool loadMore = false,
}) async { }) async {
if (isLoading == true) return -2; if (isLoading || isNextPageLoading) return -2;
isLoading = true; if (loadMore) {
isNextPageLoading = true;
pageNo += 1;
} else {
isLoading = true;
pageNo = 1; // reset pagination
}
notifyListeners();
try { try {
final payload = { final payload = {
"pageSize": pageItemNumber, "pageSize": pageItemNumber,
"pageNumber": pageNo, "pageNumber": pageNo,
"sessionId": sessionId, "sessionId": sessionId,
}; };
final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload); final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload);
stateCode = response.statusCode; stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body); final Map<String, dynamic> jsonData = json.decode(response.body);
final newResponse = AssetInventoryResponse.fromJson(jsonData); final newResponse = AssetInventoryResponse.fromJson(jsonData);
if (pageNo == 1) {
assetInventoryResponse = newResponse; if (loadMore) {
sessionAssetList = newResponse.assetList ?? []; assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
assetInventoryResponse?.totalRows = newResponse.totalRows;
} else { } else {
sessionAssetList.addAll(newResponse.assetList ?? []); assetInventoryResponse = newResponse;
assetInventoryResponse?.totalRows = newResponse.totalRows; // update total rows
} }
if ((sessionAssetList.length) < (assetInventoryResponse?.totalRows ?? 0)) { nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
nextPage = true; } else {
nextPage = false;
}
isLoading = false;
isNextPageLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
isNextPageLoading = false;
stateCode = -1;
nextPage = false;
notifyListeners();
return -1;
}
}
///older code
// Future<int> getAssetsInSession({
// required int sessionId,
// bool loadMore = false,
// }) async {
// // if (isLoading || nextPage) return -2;
//
// if (loadMore) {
// nextPage = true;
// pageNo += 1;
// } else {
// isLoading = true;
// pageNo = 1; // reset pagination
// }
//
// notifyListeners();
// log('Fetching page: $pageNo');
//
// try {
// final payload = {
// "pageSize": pageItemNumber,
// "pageNumber": pageNo,
// "sessionId": sessionId,
// };
//
// final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload);
// stateCode = response.statusCode;
//
// if (response.statusCode >= 200 && response.statusCode < 300) {
// final Map<String, dynamic> jsonData = json.decode(response.body);
// final newResponse = AssetInventoryResponse.fromJson(jsonData);
//
// if (loadMore) {
// assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
// assetInventoryResponse?.totalRows = newResponse.totalRows;
// } else {
// assetInventoryResponse = newResponse;
// }
//
// nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
// }
//
// isLoading = false;
// nextPage = false;
// notifyListeners();
// return response.statusCode;
// } catch (error) {
// isLoading = false;
// nextPage = false;
// stateCode = -1;
// notifyListeners();
// return -1;
// }
// }
Future<int> getInventoryDetailsByFilter({
required Map<String, dynamic> payload,
bool loadMore = false,
}) async {
if (isLoading || isNextPageLoading) return -2;
if (loadMore) {
isNextPageLoading = true;
pageNo += 1;
} else {
isLoading = true;
pageNo = 1;
}
notifyListeners();
log('Fetching inventory page: $pageNo');
try {
final paginatedPayload = {
...payload,
"pageSize": pageItemNumber,
"pageNumber": pageNo,
};
final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body);
final newResponse = AssetInventoryResponse.fromJson(jsonData);
if (loadMore) {
siteFilterAssetList.addAll(newResponse.assetList ?? []);
siteFilterAssetResponse?.totalRows = newResponse.totalRows;
} else { } else {
nextPage = false; siteFilterAssetResponse = newResponse;
siteFilterAssetList = newResponse.assetList ?? [];
} }
nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0);
} else {
siteFilterAssetList = [];
nextPage = false;
}
isLoading = false;
isNextPageLoading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
isLoading = false;
isNextPageLoading = false;
nextPage = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
Future<AssetInventoryModel?> searchAsset({
required Map<String, dynamic> payload,
}) async {
isLoading = true;
try {
final response = await ApiManager.instance.post(URLs.searchAsset, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
final Map<String, dynamic> jsonData = json.decode(response.body)["data"];
AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData);
log('model json ${model.toJson()}');
isLoading = false;
notifyListeners();
return model;
} else {
isLoading = false;
notifyListeners();
return null;
}
} catch (error) {
isLoading = false;
stateCode = -1;
notifyListeners();
return null;
}
}
Future<bool> saveAssetInSession({
AssetInventoryModel? model,
}) async {
isLoading = true;
try {
log('payload i got is ${model?.toJson()}');
final response = await ApiManager.instance.post(URLs.saveAssetInSession, body: model?.toJson() ?? {});
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; return true;
} else { } else {
sessionAssetList = [];
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
return response.statusCode; return false;
}
} catch (error) {
isLoading = false;
notifyListeners();
return false;
}
}
Future<bool> deleteAssetISession({required num id}) async {
try {
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
notifyListeners();
return true;
}
isLoading = false;
notifyListeners();
return false;
} catch (e) {
log("Delete Asset [error] : $e");
isLoading = false;
notifyListeners();
return false;
}
}
Future<List<Lookup>> getAutoCompleteDetails({
bool? isManufacturer,
String? query,
int type = 0,
}) async {
try {
String url = '';
switch (type) {
//for model and manufacturer..
case 0:
url = URLs.getManufacturerOrModelAutoComplete;
break;
//for asset name..
case 1:
url = URLs.searchAssetName;
break;
//for supplier...
case 2:
url = URLs.getSuppliersAutoCompleteInventory;
break;
default:
url = URLs.getManufacturerOrModelAutoComplete;
}
final queryParams = <String, String>{};
if (isManufacturer != null && type == 0) {
queryParams['isManufacturer'] = isManufacturer.toString();
}
if (query != null && query.isNotEmpty) {
queryParams['searchText'] = query;
}
if (queryParams.isNotEmpty) {
url += '?${Uri(queryParameters: queryParams).query}';
}
final response = await ApiManager.instance.get(url);
List<Lookup> list = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
final data = json.decode(response.body)["data"];
list = (data as List).map((e) => Lookup.fromJson(e)).toList();
} }
return list;
} catch (error) {
log('error $error');
return [];
}
}
Future<int> getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async {
if (isLoading == true) return -2;
isLoading = true;
notifyListeners();
late Response response;
try {
final Map<String, dynamic> body = {
"pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber,
"pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1,
"sessionId": sessionId ?? 0,
"assetSerialNo": search?.assetSerialNumber ?? '',
"assetName": search?.assetName ?? '',
"model": search?.model ?? '',
"manufacturer": search?.manufacturer ?? '',
"supplier": search?.supplier ?? '',
"siteName": search?.site ?? '',
// "buildingName":search?.??'',
// "floorName": search?.f??'',
"departmentName": search?.department ?? '',
// "roomName": search?.room
};
// if (search != null) body.addAll(search.toJson());
response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body);
} catch (error) { } catch (error) {
isLoading = false; isLoading = false;
stateCode = -1; stateCode = -1;
notifyListeners(); notifyListeners();
return -1; return -1;
} }
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List equipmentListJson = json.decode(response.body)["data"];
var dList = equipmentListJson.map<AssetInventoryModel>((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? [];
isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList);
nextPage = true;
} else {
nextPage = false;
}
isLoading = false;
notifyListeners();
return response.statusCode;
} }
Future<bool> markAsComplete({
required Map<String, dynamic> payload,
}) async {
isLoading = true;
try {
final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
isLoading = false;
notifyListeners();
return true;
} else {
isLoading = false;
notifyListeners();
return false;
}
} catch (error) {
isLoading = false;
notifyListeners();
return false;
}
}
} }

@ -30,8 +30,7 @@ class RequestItemViewList extends StatelessWidget {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading); if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
switch (list[index].transactionType) { switch (list[index].transactionType) {
case 1: case 1:
// return ServiceRequestItemView(requestDetails: list[index]); return ServiceRequestItemView(requestDetails: list[index]);
return InventorySessionCard(requestDetails: list[index]);
case 2: case 2:
return GasRefillItemView(requestDetails: list[index]); return GasRefillItemView(requestDetails: list[index]);
case 3: case 3:

@ -26,6 +26,7 @@ class AssetPicker extends StatelessWidget {
Color? backgroundColor; Color? backgroundColor;
final bool forPPM; final bool forPPM;
final bool showLoading; final bool showLoading;
final bool enablePickManually;
final bool multiSelection; final bool multiSelection;
AssetPicker( AssetPicker(
@ -45,7 +46,7 @@ class AssetPicker extends StatelessWidget {
this.showAssetInfo = true, this.showAssetInfo = true,
this.showBorder = false, this.showBorder = false,
this.multiSelection = false, this.multiSelection = false,
this.forPPM = false, this.forPPM = false, this.enablePickManually = true,
this.showLoading = false}) this.showLoading = false})
: assert( : assert(
multiSelection == false || onMultiAssetPick != null, multiSelection == false || onMultiAssetPick != null,
@ -83,6 +84,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?; ))) as List<Asset>?;
if (device?.isNotEmpty ?? false) { if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!); onMultiAssetPick!(device!);
@ -92,6 +94,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?; ))) as Asset?;
if (device != null) { if (device != null) {
onPick!(device); onPick!(device);
@ -121,6 +124,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?; ))) as List<Asset>?;
if (device?.isNotEmpty ?? false) { if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!); onMultiAssetPick!(device!);
@ -130,6 +134,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?; ))) as Asset?;
if (device != null) { if (device != null) {
onPick!(device); onPick!(device);
@ -140,7 +145,7 @@ class AssetPicker extends StatelessWidget {
if (deviceList.isNotEmpty && showAssetInfo) if (deviceList.isNotEmpty && showAssetInfo)
ListView.separated( ListView.separated(
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only(top: 16), padding: const EdgeInsets.only(top: 16),
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context), itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context),
separatorBuilder: (cxt, index) => 12.height, separatorBuilder: (cxt, index) => 12.height,
@ -204,10 +209,10 @@ class AssetPicker extends StatelessWidget {
], ],
), ),
8.height, 8.height,
"${context.translation.assetNo}: ${device!.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context), "${context.translation.assetNo}: ${device.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
2.height, 2.height,
// "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context), // "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context),
"${context.translation.model}: ${device!.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context), "${context.translation.model}: ${device.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
// "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context), // "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context),
// const Divider().defaultStyle(context), // const Divider().defaultStyle(context),
// "${context.translation.department}: ${device.department?.departmentName}".bodyText(context), // "${context.translation.department}: ${device.department?.departmentName}".bodyText(context),

@ -20,9 +20,10 @@ import '../../pages/device_transfer/search_device_page.dart';
class AssetScanQr extends StatefulWidget { class AssetScanQr extends StatefulWidget {
static const String id = "/asset-scan-qr"; static const String id = "/asset-scan-qr";
const AssetScanQr({Key? key, required this.title, this.multiSelection = false}) : super(key: key); const AssetScanQr({Key? key, required this.title, this.multiSelection = false,this.enablePickManually = true}) : super(key: key);
final String title; final String title;
final bool multiSelection; final bool multiSelection;
final bool enablePickManually;
@override @override
_AssetScanQrState createState() => _AssetScanQrState(); _AssetScanQrState createState() => _AssetScanQrState();
@ -86,15 +87,23 @@ class _AssetScanQrState extends State<AssetScanQr> {
controller.scannedDataStream.listen((scanData) async { controller.scannedDataStream.listen((scanData) async {
if (!_scanDone) { if (!_scanDone) {
_scanDone = true; _scanDone = true;
final result = await _getDevice(scanData.code!, isQr: true); if(!widget.enablePickManually){
if (result.isNotEmpty) { if(scanData.code!=null){
if (widget.multiSelection) { Navigator.of(context).pop(Asset(assetNumber: scanData.code!));
Navigator.of(context).pop(<Asset>[result[0]]); }else{
_scanDone = false;
}
}else{
final result = await _getDevice(scanData.code!, isQr: true);
if (result.isNotEmpty) {
if (widget.multiSelection) {
Navigator.of(context).pop(<Asset>[result[0]]);
} else {
Navigator.of(context).pop(result[0]);
}
} else { } else {
Navigator.of(context).pop(result[0]); _scanDone = false;
} }
} else {
_scanDone = false;
} }
} }
}); });
@ -109,7 +118,8 @@ class _AssetScanQrState extends State<AssetScanQr> {
), ),
], ],
).expanded, ).expanded,
FooterActionButton.footerContainer( if(widget.enablePickManually)
FooterActionButton.footerContainer(
context: context, context: context,
child: AppFilledButton( child: AppFilledButton(
label: context.translation.pickManually, label: context.translation.pickManually,

Loading…
Cancel
Save