Merge pull request 'zaid_development_new' (#1) from zaid_development_new into main_latest_merged

Reviewed-on: http://34.17.52.79/Haroon6138/cloudsolutions-atoms/pulls/1
main_latest_merged
Sikander Saleem 1 year ago
commit 45a1707352

@ -54,22 +54,25 @@ android {
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
// release {
// keyAlias keystoreProperties['keyAlias']
// keyPassword keystoreProperties['keyPassword']
// storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
// storePassword keystoreProperties['storePassword']
// }
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
signingConfig signingConfigs.debug
}
// release {
// minifyEnabled true
// shrinkResources true
// signingConfig signingConfigs.release
// }
}
}

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="50.481" height="50.488" viewBox="0 0 50.481 50.488">
<g id="research_1_" data-name="research (1)" transform="translate(-2 -2)">
<path id="Path_4616" data-name="Path 4616" d="M9.2,15H3.8A1.8,1.8,0,0,0,2,16.8V31.226a1.8,1.8,0,0,0,1.8,1.8H18.226a1.8,1.8,0,0,0,1.8-1.8v-.937a16.379,16.379,0,0,1-6.094-3.858A16.215,16.215,0,0,1,9.2,15Z" transform="translate(0 10.437)" fill="#5bb0d9"/>
<path id="Path_4617" data-name="Path 4617" d="M3.8,20.028h6.292a15.865,15.865,0,0,1,3.84-6.094,16.379,16.379,0,0,1,6.094-3.856V3.8a1.8,1.8,0,0,0-1.8-1.8H3.8A1.8,1.8,0,0,0,2,3.8V18.226a1.8,1.8,0,0,0,1.8,1.8ZM7.03,9.41a1.785,1.785,0,0,1,2.56,0l.739.739,2.109-2.091A1.8,1.8,0,0,1,15,10.6l-3.389,3.371a1.763,1.763,0,0,1-2.542,0L7.03,11.952a1.8,1.8,0,0,1,0-2.54Z" fill="#5bb0d9"/>
<path id="Path_4618" data-name="Path 4618" d="M46.922,39.274a1.945,1.945,0,0,0-.22-.193L37.78,32.706a1.8,1.8,0,0,0-2.322.193L32.82,30.262a14.452,14.452,0,1,0-2.558,2.558L32.9,35.458a1.8,1.8,0,0,0-.193,2.322L39.081,46.7a1.785,1.785,0,0,0,.193.227,5.408,5.408,0,1,0,7.648-7.648Zm-33.145-10.2a10.817,10.817,0,1,1,7.648,3.168,10.817,10.817,0,0,1-7.648-3.168Z" transform="translate(3.975 3.975)" fill="#5bb0d9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -201,6 +201,8 @@
"repairLocation" : "موقع الإصلاح",
"travelingExpense" : "مصاريف التنقل",
"startDate" : "وقت البدء",
"requestedQuantity" : "الكمية المطلوبة",
"deliveredQuantity" : "الكمية المسلّمة",
"endDate" : "وقت الانتهاء",
"destinationSite": "موقع الوجهه",
"building": "بناء",

@ -201,6 +201,8 @@
"repairLocation" : "Repair Location",
"travelingExpense": "Traveling Expense",
"startDate" : "Start Date",
"requestedQuantity" : "Requested Quantity",
"deliveredQuantity" : "Delivered Quantity",
"endDate" : "End Date",
"destinationSite": "Destination Site",
"building": "Building",
@ -208,6 +210,4 @@
"department": "Department",
"room": "Room",
"actions": "Actions"
}

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
@ -51,9 +52,12 @@ class ApiManager {
headers.addAll(_headers);
Uri _url = Uri.parse(url);
// print(_url);
// print(headers);
// log(json.encode(body));
if (!kReleaseMode) {
print("URL:$_url");
print("Headers:$headers");
print("Body:$body");
}
var request = http.Request('POST', _url);
request.body = json.encode(body);
request.headers.addAll(headers);
@ -83,7 +87,7 @@ class ApiManager {
headers.addAll(_headers);
Uri _url = Uri.parse(url);
// print(_url);
print(_url);
// print(headers);
// log(json.encode(body));
var request = http.Request('PUT', _url);

@ -36,6 +36,9 @@ class URLs {
static get getRepairLocation => "$_baseUrl/Lookups/GetLookup?lookupEnum=504";
static get equipmentStatus => "$_baseUrl/Lookups/GetLookup?lookupEnum=601";
static get getDateOperators => "$_baseUrl/Lookups/GetLookup?lookupEnum=200";
static get getMaintenanceSituation => "$_baseUrl/Lookups/GetLookup?lookupEnum=502";
static get getAllUsers => "http://109.123.243.118:5000/api/Account/GetAllUsers";
static get getPreventiveMaintenanceVisits => "$_baseUrl/return/user/calibrations"; // get
static get updatePreventiveMaintenanceVisits => "$_baseUrl/Visit/UpdateVisits"; // get

@ -23,7 +23,7 @@ class DeviceTransferProvider extends ChangeNotifier {
building = null;
floor = null;
department = null;
room="";
room = "";
startDate = null;
endDate = null;
}
@ -44,7 +44,6 @@ class DeviceTransferProvider extends ChangeNotifier {
// failed _loading = false
bool isLoading;
Hospital hospital;
Buildings building;
Floors floor;
@ -115,7 +114,7 @@ class DeviceTransferProvider extends ChangeNotifier {
// "transferCode": "string",
"destBuildingId": building?.id,
"destFloorId": floor.id,
"destRoom": room,
"destRoom": room,
// "senderBuildingId": 0,
// "senderFloorId": 0,
// "senderDepartmentId": 0,
@ -179,8 +178,8 @@ class DeviceTransferProvider extends ChangeNotifier {
"senderMachineStatusId": newModel.status.id,
"senderComment": newModel.comment,
"senderWorkingHours": newModel.workingHours,
"senderStartDate": newModel.startDate?.toIso8601String(),
"senderEndDate": newModel.endDate?.toIso8601String(),
"senderStartDate": newModel.timer?.startAt?.toIso8601String(),
"senderEndDate": newModel.timer?.endAt?.toIso8601String(),
"senderTravelingHours": newModel.travelingHours,
"senderAttachmentName": "${newModel.signature}.png",
"destSiteId": oldModel.receiver.client.id,
@ -189,8 +188,8 @@ class DeviceTransferProvider extends ChangeNotifier {
"receiverMachineStatusId": oldModel.receiver.status.id ?? "",
"receiverComment": oldModel.receiver.comment,
"receiverWorkingHours": oldModel.receiver.workingHours,
"receiverStartDate": oldModel.receiver.startDate?.toIso8601String(),
"receiverEndDate": oldModel.receiver.endDate?.toIso8601String(),
"receiverStartDate": oldModel.receiver.timer?.startAt?.toIso8601String(),
"receiverEndDate": oldModel.receiver.timer?.endAt?.toIso8601String(),
"receiverTravelingHours": oldModel.receiver.travelingHours,
"receiverAttachmentName": "${oldModel.receiver.signature}.png",
});
@ -202,8 +201,8 @@ class DeviceTransferProvider extends ChangeNotifier {
"senderMachineStatusId": oldModel.sender.status.id,
"senderComment": oldModel.sender.comment,
"senderWorkingHours": oldModel.sender.workingHours,
"senderStartDate": oldModel.sender.startDate?.toIso8601String(),
"senderEndDate": oldModel.sender.endDate?.toIso8601String(),
"senderStartDate": oldModel.sender.timer?.startAt?.toIso8601String(),
"senderEndDate": oldModel.sender.timer?.endAt?.toIso8601String(),
"senderTravelingHours": oldModel.sender.travelingHours,
"senderAttachmentName": "${oldModel.sender.signature}.png",
"destSiteId": newModel.client.id,
@ -212,8 +211,8 @@ class DeviceTransferProvider extends ChangeNotifier {
"receiverMachineStatusId": newModel.status?.id ?? "",
"receiverComment": newModel.comment,
"receiverWorkingHours": newModel.workingHours,
"receiverStartDate": newModel.startDate?.toIso8601String(),
"receiverEndDate": newModel.endDate?.toIso8601String(),
"receiverStartDate": newModel.timer?.startAt?.toIso8601String(),
"receiverEndDate": newModel.timer?.endAt?.toIso8601String(),
"receiverTravelingHours": newModel.travelingHours,
"receiverAttachmentName": "${newModel.signature}.png",
});
@ -247,5 +246,4 @@ class DeviceTransferProvider extends ChangeNotifier {
return -1;
}
}
}

@ -147,31 +147,31 @@ class DevicesProvider extends ChangeNotifier {
}
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<List<Device>> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async {
Response response;
try {
response = await get(
Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")),
);
_stateCode = response.statusCode;
List<Device> _page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
_page = categoriesListJson.map((device) => Device.fromJson(device)).toList();
}
return _page;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return [];
}
}
// /// return -2 if request in progress
// /// return -1 if error happen when sending request
// /// return state code if request complete may be 200, 404 or 403
// /// for more details check http state manager
// /// lib\controllers\http_status_manger\http_status_manger.dart
// Future<List<Device>> getDevicesListBySN({@required String host, @required User user, @required int hospitalId, @required String sn}) async {
// Response response;
// try {
// response = await get(
// Uri.parse(URLs.getEquipment + "?client=$hospitalId" + (sn == null || sn.isEmpty ? "" : "&serial_qr=$sn")),
// );
//
// _stateCode = response.statusCode;
// List<Device> _page = [];
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
// _page = categoriesListJson.map((device) => Device.fromJson(device)).toList();
// }
// return _page;
// } catch (error) {
// _loading = false;
// _stateCode = -1;
// notifyListeners();
// return [];
// }
// }
}

@ -91,22 +91,24 @@ class GasRefillProvider extends ChangeNotifier {
@required User user,
@required GasRefillModel model,
}) async {
print("ss");
Map<String, dynamic> body = {
"uid": user.id.toString(),
"token": user.token ?? "",
"site": hospital?.toMap(),
"building": {"id": building?.id, "name": building?.name, "value": building?.value},
"floor": {"id": floor.id, "name": floor.name, "value": floor.value},
if (expectedDateTime != null) "expectedDate": expectedDateTime,
if (expectedDateTime != null) "expectedTime": expectedDateTime,
if (startDate != null) "startDate": startDate,
if (startDate != null) "startTime": startDate,
if (endDate != null) "endDate": endDate,
if (endDate != null) "endTime": endDate,
"department": {"id": department.id, "departmentName": department.name, "departmentCode": "", "ntCode": ""},
"floor": {"id": floor?.id, "name": floor?.name, "value": floor?.value},
if (expectedDateTime != null) "expectedDate": expectedDateTime?.toIso8601String(),
if (expectedDateTime != null) "expectedTime": expectedDateTime?.toIso8601String(),
if (startDate != null) "startDate": startDate?.toIso8601String(),
if (startDate != null) "startTime": startDate?.toIso8601String(),
if (endDate != null) "endDate": endDate?.toIso8601String(),
if (endDate != null) "endTime": endDate?.toIso8601String(),
"department": {"id": department?.id, "departmentName": department?.name, "departmentCode": "", "ntCode": ""},
"GazRefillNo": "GR-${DateTime.now().toString().split(" ").first}",
"status": model.status.toMap(),
};
print("ss1");
body["gazRefillDetails"] = model.details
.map((model) => {
"gasType": model.type.toMap(),
@ -119,6 +121,7 @@ class GasRefillProvider extends ChangeNotifier {
Response response;
try {
response = await ApiManager.instance.post(URLs.requestGasRefill, body: body);
print("ss2");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
if (items != null) {
@ -128,6 +131,7 @@ class GasRefillProvider extends ChangeNotifier {
}
return response.statusCode;
} catch (error) {
print(error);
return -1;
}
}
@ -142,6 +146,20 @@ class GasRefillProvider extends ChangeNotifier {
"id": newModel.id,
"gazRefillNo": newModel.title ?? "",
"status": newModel.status.toMap(),
"expectedDate": oldModel.expectedDate?.toIso8601String(),
"expectedTime": oldModel.expectedDate?.toIso8601String(),
"startDate": startDate?.toIso8601String(),
"startTime": startDate?.toIso8601String(),
"endDate": endDate?.toIso8601String(),
"endTime": endDate?.toIso8601String(),
"workingHours": ((endDate?.difference(startDate)?.inMinutes ?? 0) / 60),
"assignedEmployee": oldModel?.assignedEmployee?.id == null ? null : oldModel?.assignedEmployee?.toJson(),
"site": hospital?.toMap(),
"building": building?.toJson(includeFloors: false),
"floor": floor?.toJson(includeDepartments: false),
"department": department?.toJson(),
"engSignature": newModel.signatureEngineer,
"nurseSignature": newModel.signatureNurse,
};
body["gazRefillDetails"] = newModel.details

@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';
@ -7,14 +8,15 @@ import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/call_request_for_work_order_model.dart';
import 'package:test_sa/models/issue.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/service_request/service_request_search.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/models/user.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/user.dart';
class ServiceRequestsProvider extends ChangeNotifier {
// number of items call in each request
@ -22,6 +24,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
//reset provider data
void reset() {
workOrders = [];
serviceRequests = null;
nextPage = true;
stateCode = null;
@ -37,7 +40,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
// list of user requests
List<ServiceRequest> serviceRequests;
List<SearchWorkOrders> workOrders = [];
List<SearchWorkOrder> workOrders = [];
// when requests in-process _loading = true
// done _loading = true
@ -51,11 +54,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getRequests({
@required String host,
@required User user,
@required int hospitalId,
}) async {
Future<int> getRequests({@required int hospitalId}) async {
if (isLoading == true) return -2;
isLoading = true;
if (serviceRequests == null) notifyListeners();
@ -237,6 +236,10 @@ class ServiceRequestsProvider extends ChangeNotifier {
"voiceNote": request.audio,
"assets": request.deviceId == null ? [] : [request.deviceId],
"attachmentsCallRequest": request.devicePhotos?.map((e) => {"name": e})?.toList(),
"assignedEmployee": {
"id": request.engineerId,
"name": request.engineerName,
},
"callSiteContactPerson": [
{
"id": callSiteContactPerson['id'] ?? 0,
@ -318,9 +321,9 @@ class ServiceRequestsProvider extends ChangeNotifier {
"currentSituation": null,
"repairLocation": report.repairLocation?.toMap(),
"reason": report.reason?.toMap(),
"startofWorkTime": report.startDate?.toIso8601String() ?? "",
"endofWorkTime": report.endDate?.toIso8601String() ?? "",
"workingHours": ((report?.endDate?.difference(report?.startDate)?.inMinutes ?? 0) / 60),
"startofWorkTime": report.timer?.startAt?.toIso8601String() ?? "",
"endofWorkTime": report.timer?.endAt?.toIso8601String() ?? "",
"workingHours": report?.workingHours,
"travelingHours": report.travelingHours,
"travelingExpenses": report.travelingExpense ?? 0,
if (report.faultDescription != null) "faultDescription": report.faultDescription.toJson(),
@ -364,6 +367,27 @@ class ServiceRequestsProvider extends ChangeNotifier {
}
}
Future<int> createSubWorkOrder({
@required SearchWorkOrder workOrder,
}) async {
Response response;
try {
Map<String, dynamic> body = workOrder.toJson();
response = await ApiManager.instance.post(URLs.createServiceReport, body: body);
print(response.body);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
reset();
notifyListeners();
}
return response.statusCode;
} catch (error) {
print(error);
return -1;
}
}
CallRequestForWorkOrder callRequestForWorkOrder;
Future<CallRequestForWorkOrder> getCallRequestForWorkOrder({String callId}) async {
@ -376,17 +400,19 @@ class ServiceRequestsProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
Map<String, dynamic> listJson = json.decode(response.body)["data"];
log(listJson?.toString());
callRequestForWorkOrder = CallRequestForWorkOrder.fromJson(listJson);
}
notifyListeners();
return callRequestForWorkOrder;
} catch (error) {
print(error);
return null;
}
}
Future<List<SearchWorkOrders>> searchWorkOrders({@required String callId}) async {
Future<List<SearchWorkOrder>> searchWorkOrders({@required String callId}) async {
Response response;
try {
@ -401,7 +427,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
// client's request was successfully received
List workOrdersJson = json.decode(response.body)["data"];
print(workOrdersJson);
workOrders = workOrdersJson.map<SearchWorkOrders>((request) => SearchWorkOrders.fromJson(request)).toList();
workOrders = workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList();
if (workOrders.length == pageItemNumber) {
nextPage = true;
} else {
@ -444,11 +470,41 @@ class ServiceRequestsProvider extends ChangeNotifier {
}
Future<int> updateServiceReport({
@required String host,
@required User user,
@required ServiceReport report,
@required ServiceRequest request,
String host,
User user,
ServiceRequest request,
}) async {
Response response;
//Map<String,dynamic> body = report.toMap(request);
// body["uid"] = user.id;
// body["token"] = user.token;
// body["job_id"] = request.id;
// body["report_id"] = request.reportID;
// try {
Map<String, dynamic> body = report.toMap(request);
// body["uid"] = user.id;
// body["token"] = user.token;
response = await ApiManager.instance.put(URLs.updateServiceReport, body: body);
// response = await post(
// Uri.parse(
// host+URLs.updateServiceReport),
// body: body,
// );
// stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
reset();
notifyListeners();
}
return response.statusCode;
// } catch (error) {
// print(error);
// return -1;
// }
}
Future<int> updateWorkOrderDetails({@required SearchWorkOrder workOrder}) async {
Response response;
//Map<String,dynamic> body = report.toMap(request);
// body["uid"] = user.id;
@ -456,7 +512,7 @@ class ServiceRequestsProvider extends ChangeNotifier {
// body["job_id"] = request.id;
// body["report_id"] = request.reportID;
try {
Map<String, dynamic> body = report.toMap(request);
Map<String, dynamic> body = workOrder.toJson();
// body["uid"] = user.id;
// body["token"] = user.token;
response = await ApiManager.instance.put(URLs.updateServiceReport, body: body);
@ -557,4 +613,51 @@ class ServiceRequestsProvider extends ChangeNotifier {
return {};
}
}
Future<List<SearchWorkOrder>> searchForWorkOrders(
SearchWorkOrder search,
String callerId,
Lookup dateOperator,
String site,
) async {
Response response;
try {
var body = {
"pageSize": pageItemNumber,
"pageNumber": ((workOrders?.length ?? 0) ~/ pageItemNumber) + 1,
if (callerId?.isNotEmpty ?? false) "callId": callerId,
if (search.assetType != null) "assetSerialNo": search.assetType?.name,
if (search.workOrderNo != null) "workOrderNo": search.workOrderNo,
if (search.id != null) "workOrderNo": search.id?.toString(),
if (search.calllastSituation != null) "callslastSituationWO": search.calllastSituation.toMap(),
if (search.assignedEmployee != null)
"assignedEmployees": [
search.assignedEmployee.id,
],
// "statusWO": [],
if (site?.isNotEmpty ?? false) "site": site,
if (search.visitDate != null && dateOperator != null) "visitDateSymbol": dateOperator?.toMap(),
if (search.visitDate != null && dateOperator != null) "visitDateFrom": search.visitDate,
};
print(body);
response = await ApiManager.instance.post(URLs.searchWorkOrders, body: body);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List workOrdersJson = json.decode(response.body)["data"];
print(workOrdersJson);
workOrders ??= [];
workOrders.addAll(workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList());
if (workOrders.length == pageItemNumber) {
nextPage = true;
} else {
nextPage = false;
}
}
return workOrders;
} catch (e) {
print(e);
return [];
}
}
}

@ -0,0 +1,76 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
class ServiceReportAssistantsEmployeeProvider extends ChangeNotifier {
//reset provider data
void reset() {
_assistantEmployees = null;
_loading = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// contain user data
// when user not login or register _user = null
List<AssistantEmployees> _assistantEmployees;
List<AssistantEmployees> get assistantEmployees => _assistantEmployees;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getAssistantEmployees() async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(
"${URLs.getEngineers}",
);
// response = await get(
// Uri.parse(
// URLs.getServiceReportLastCalls
// +(serviceStatus == null ? "" : "?service_status=$serviceStatus")
// ),
// );
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List usersListJson = json.decode(response.body);
_assistantEmployees = [];
_assistantEmployees = usersListJson.map((type) => AssistantEmployees.fromJson(type ?? {})).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -55,7 +55,7 @@ class ServiceRequestFaultDescriptionProvider extends ChangeNotifier {
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List listJson = json.decode(response.body)["data"]['asset']['modelDefinition']['modelDefRelatedDefects'];
_items = listJson.map((type) => FaultDescription.fromJson(type)).toList();
_items = listJson?.map((type) => FaultDescription.fromJson(type))?.toList() ?? [];
}
_loading = false;
notifyListeners();

@ -57,7 +57,7 @@ class ServiceReportLastCallsProvider extends ChangeNotifier {
try {
// todo request new api from backend to make filter work
response = await ApiManager.instance.get(
"${URLs.getServiceReportLastCalls}?parentWOId=$woId&isAdd=true&id=${id ?? 0}&typeTransaction=$typeName",
"${URLs.getServiceReportLastCalls}?parentWOId=${woId??id}&isAdd=true&id=${id ?? 0}&typeTransaction=$typeName",
);
// response = await get(
// Uri.parse(

@ -0,0 +1,75 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
class ServiceReportMaintenanceSituationProvider extends ChangeNotifier {
//reset provider data
void reset() {
_calls = null;
_loading = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// contain user data
// when user not login or register _user = null
List<Lookup> _calls;
List<Lookup> get operators => _calls;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getOperators(String woId) async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(
woId == null ? "${URLs.getMaintenanceSituation}" : "${URLs.getServiceReportLastCalls}?parentWOId=$woId&isAdd=true&id=${0}&typeTransaction='Nothing'",
);
// response = await get(
// Uri.parse(
// URLs.getServiceReportLastCalls
// +(serviceStatus == null ? "" : "?service_status=$serviceStatus")
// ),
// );
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
_calls = categoriesListJson.map((type) => Lookup.fromJson(type)).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,75 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/engineer.dart';
class ServiceReportUsersProvider extends ChangeNotifier {
//reset provider data
void reset() {
_engineers = null;
_loading = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// contain user data
// when user not login or register _user = null
List<Engineer> _engineers;
List<Engineer> get engineers => _engineers;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getAllUsers() async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(
"${URLs.getAllUsers}",
);
// response = await get(
// Uri.parse(
// URLs.getServiceReportLastCalls
// +(serviceStatus == null ? "" : "?service_status=$serviceStatus")
// ),
// );
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List usersListJson = json.decode(response.body);
_engineers = usersListJson.map((type) => Engineer.fromJson(type)).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,75 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/lookup.dart';
class ServiceReportVisitOperatorProvider extends ChangeNotifier {
//reset provider data
void reset() {
_calls = null;
_loading = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int _stateCode;
int get stateCode => _stateCode;
// contain user data
// when user not login or register _user = null
List<Lookup> _calls;
List<Lookup> get operators => _calls;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<int> getOperators() async {
if (_loading == true) return -2;
_loading = true;
notifyListeners();
Response response;
try {
response = await ApiManager.instance.get(
"${URLs.getDateOperators}",
);
// response = await get(
// Uri.parse(
// URLs.getServiceReportLastCalls
// +(serviceStatus == null ? "" : "?service_status=$serviceStatus")
// ),
// );
_stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
_calls = categoriesListJson.map((type) => Lookup.fromJson(type)).toList();
}
_loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
_loading = false;
_stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -23,7 +23,10 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/pentry/pentry
import 'package:test_sa/controllers/providers/api/status_drop_down/pentry/pentry_visit_status_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_defect_types_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_equipment_status_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_priority_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_users_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_visit_date_operator_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/service_reqest/service_request_first_action_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/service_reqest/service_request_loan_availability_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/service_reqest/service_request_status_provider.dart';
@ -33,6 +36,8 @@ import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/pages/login.dart';
import 'package:test_sa/views/pages/register.dart';
import 'package:test_sa/views/pages/splash_screen.dart';
import 'package:test_sa/views/pages/sub_workorder/create_sub_workorder_page.dart';
import 'package:test_sa/views/pages/sub_workorder/search_sub_workorder_page.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/pages/user/gas_refill/track_gas_refill.dart';
import 'package:test_sa/views/pages/user/land_page.dart';
@ -50,6 +55,7 @@ import 'package:test_sa/views/widgets/equipment/single_device_picker.dart';
import 'controllers/providers/api/parts_provider.dart';
import 'controllers/providers/api/preventive_maintenance_visits_provider.dart';
import 'controllers/providers/api/status_drop_down/pentry/pentry_status_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_assistants_employee_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'controllers/providers/api/status_drop_down/report/service_report_reasons_provider.dart';
@ -121,6 +127,10 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceFirstActionProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportVisitOperatorProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportAssistantsEmployeeProvider()),
],
child: GestureDetector(
onTap: () {
@ -172,6 +182,8 @@ class MyApp extends StatelessWidget {
TrackGasRefillPage.id: (_) => const TrackGasRefillPage(),
RequestDeviceTransfer.id: (_) => const RequestDeviceTransfer(),
TrackDeviceTransferPage.id: (_) => const TrackDeviceTransferPage(),
SearchSubWorkOrderPage.id: (_) => const SearchSubWorkOrderPage(),
CreateSubWorkOrderPage.id: (_) => const CreateSubWorkOrderPage(),
},
),
),

@ -82,7 +82,7 @@ class Asset {
Department department;
String room;
String testsDay;
String purchasingPrice;
num purchasingPrice;
String nbv;
String currency;
String poNo;
@ -328,7 +328,7 @@ class ModelDefinition {
if (json['suppliers'] != null) {
suppliers = [];
json['suppliers'].forEach((v) {
// suppliers!.add(new Null.fromJson(v));
// suppliers!.add(new Null.fromJson(v));
});
}
}
@ -394,7 +394,7 @@ class Site {
if (json['buildings'] != null) {
buildings = [];
json['buildings'].forEach((v) {
// buildings!.add(new Null.fromJson(v));
// buildings!.add(new Null.fromJson(v));
});
}
}
@ -427,11 +427,11 @@ class Department {
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['departmentName'] = this.departmentName;
data['departmentCode'] = this.departmentCode;
data['ntCode'] = this.ntCode;
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['departmentName'] = departmentName;
data['departmentCode'] = departmentCode;
data['ntCode'] = ntCode;
return data;
}
}
@ -520,7 +520,7 @@ class Building {
int value;
var floor;
Building({this.id, this.name, this.value,this.floor});
Building({this.id, this.name, this.value, this.floor});
Building.fromJson(Map<String, dynamic> json) {
id = json['id'];
@ -538,4 +538,3 @@ class Building {
return data;
}
}

@ -46,7 +46,7 @@ class Data {
customerCode = json['customerCode'];
custName = json['custName'];
if (json['buildings'] != null) {
buildings = new List<Buildings>();
buildings = [];
json['buildings'].forEach((v) {
buildings.add(new Buildings.fromJson(v));
});
@ -78,7 +78,7 @@ class Buildings {
name = json['name'];
value = json['value'];
if (json['floors'] != null) {
floors = new List<Floors>();
floors = [];
json['floors'].forEach((v) {
floors.add(new Floors.fromJson(v));
});
@ -110,7 +110,7 @@ class Floors {
name = json['name'];
value = json['value'];
if (json['departments'] != null) {
departments = new List<Departments>();
departments = [];
json['departments'].forEach((v) {
departments.add(new Departments.fromJson(v));
});

@ -5,6 +5,8 @@ import 'package:test_sa/models/device/device_transfer_info.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import '../timer_model.dart';
class DeviceTransfer {
int id;
String userId;
@ -46,21 +48,26 @@ class DeviceTransfer {
title: parsedJson["transferCode"],
userId: parsedJson["uid"],
device: Device(
id: parsedJson["assetId"],
number: parsedJson["assetNumber"],
serialNumber: parsedJson["assetSerialNo"],
destBuildingName: parsedJson["destBuildingName"],
destDepartmentName: parsedJson["destDepartmentName"],
destFloor: parsedJson["destFloor"],
destRoom: parsedJson["destRoom"],
destSiteName: parsedJson["destSiteName"]
),
id: parsedJson["assetId"],
number: parsedJson["assetNumber"],
serialNumber: parsedJson["assetSerialNo"],
destBuildingName: parsedJson["destBuildingName"],
destDepartmentName: parsedJson["destDepartmentName"],
destFloor: parsedJson["destFloor"],
destRoom: parsedJson["destRoom"],
destSiteName: parsedJson["destSiteName"]),
sender: DeviceTransferInfo(
travelingHours: parsedJson["senderTravelingHours"],
comment: parsedJson["senderComment"],
workingHours: parsedJson["senderWorkingHours"],
startDate: parsedJson["senderStartDate"]==null ? null:DateTime.parse(parsedJson["senderStartDate"]),
endDate: parsedJson["senderEndDate"]==null ? null:DateTime.parse(parsedJson["senderEndDate"]),
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["senderStartDate"] ?? ""),
endAt: DateTime.tryParse(parsedJson["senderEndDate"] ?? ""),
durationInSecond: ((parsedJson["workingHours"] ?? 0) * 60 * 60).toInt(),
stopped: parsedJson["workingHours"] == null ? null : true,
),
// startDate: parsedJson["senderStartDate"] == null ? null : DateTime.parse(parsedJson["senderStartDate"]),
// endDate: parsedJson["senderEndDate"] == null ? null : DateTime.parse(parsedJson["senderEndDate"]),
userId: parsedJson["senderAssignedEmployeeId"],
userName: parsedJson["senderAssignedEmployeeName"],
assignedEmployeeName: parsedJson["senderAssignedEmployeeName"],
@ -80,8 +87,11 @@ class DeviceTransfer {
travelingHours: parsedJson["receiverTravelingHours"],
comment: parsedJson["receiverComment"],
workingHours: parsedJson["receiverWorkingHours"],
startDate: parsedJson["receiverStartDate"]==null ? null:DateTime.parse(parsedJson["receiverStartDate"]),
endDate: parsedJson["receiverEndDate"]==null ? null:DateTime.parse(parsedJson["receiverEndDate"]),
timer: parsedJson["receiverStartDate"] != null || parsedJson["receiverEndDate"] != null
? TimerModel(startAt: DateTime.tryParse(parsedJson["receiverStartDate"] ?? ""), endAt: DateTime.tryParse(parsedJson["receiverEndDate"] ?? ""))
: null,
// startDate: parsedJson["receiverStartDate"] == null ? null : DateTime.parse(parsedJson["receiverStartDate"]),
// endDate: parsedJson["receiverEndDate"] == null ? null : DateTime.parse(parsedJson["receiverEndDate"]),
userId: parsedJson["receiverAssignedEmployeeId"],
userName: parsedJson["receiverAssignedEmployeeName"],
assignedEmployeeName: parsedJson["receiverAssignedEmployeeName"],

@ -2,19 +2,22 @@ import 'package:test_sa/models/department.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import '../timer_model.dart';
class DeviceTransferInfo {
String userId;
String comment;
Hospital client;
Department department;
String workingHours;
DateTime startDate;
DateTime endDate;
// DateTime startDate;
// DateTime endDate;
String travelingHours;
String userName;
String signature;
String assignedEmployeeName;
Lookup status;
TimerModel timer;
DeviceTransferInfo({
this.userId,
@ -23,12 +26,13 @@ class DeviceTransferInfo {
this.client,
this.userName,
this.travelingHours,
this.startDate,
this.endDate,
// this.startDate,
// this.endDate,
this.workingHours,
this.signature,
this.status,
this.assignedEmployeeName
this.assignedEmployeeName,
this.timer,
});
Map<String, String> toJson(bool isSender) {
@ -37,8 +41,10 @@ class DeviceTransferInfo {
if (comment != null && comment.isNotEmpty) body["${baseKey}comment"] = comment;
if (workingHours != null && workingHours.isNotEmpty) body["${baseKey}working_hours"] = workingHours;
if (startDate != null) body["${baseKey}start_date"] = startDate?.toIso8601String();
if (endDate != null) body["${baseKey}end_date"] = endDate?.toIso8601String();
// if (startDate != null) body["${baseKey}start_date"] = startDate?.toIso8601String();
// if (endDate != null) body["${baseKey}end_date"] = endDate?.toIso8601String();
if (timer?.startAt != null) body["${baseKey}start_date"] = timer?.startAt?.toIso8601String();
if (timer?.endAt != null) body["${baseKey}end_date"] = timer?.endAt?.toIso8601String();
if (travelingHours != null && travelingHours.isNotEmpty) body["${baseKey}travel_hours"] = travelingHours;
if (status != null) body["${baseKey}status"] = status.id.toString();
if (signature != null && signature.isNotEmpty) body["${baseKey}image"] = signature;
@ -57,8 +63,9 @@ class DeviceTransferInfo {
client = Hospital.fromHospital(old.client);
department = Department.fromDepartment(old.department);
workingHours = old.workingHours;
startDate = old.startDate;
endDate = old.endDate;
// startDate = old.startDate;
// endDate = old.endDate;
timer = old.timer;
travelingHours = old.travelingHours;
comment = old.comment;
if (withSignature) signature = old.signature;
@ -68,14 +75,20 @@ class DeviceTransferInfo {
factory DeviceTransferInfo.fromJson(Map<String, dynamic> parsedJson, String key) {
return DeviceTransferInfo(
workingHours: parsedJson["${key}working_hours"],
startDate: parsedJson["${key}start_date"],
endDate: parsedJson["${key}end_date"],
// startDate: parsedJson["${key}start_date"],
// endDate: parsedJson["${key}end_date"],
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["${key}start_date"] ?? ""),
endAt: DateTime.tryParse(parsedJson["${key}end_date"] ?? ""),
durationInSecond: ((parsedJson["${key}working_hours"] ?? 0) * 60 * 60).toInt(),
stopped: parsedJson["${key}working_hours"] == null || (parsedJson["${key}working_hours"] as String).isEmpty ? null : true,
),
travelingHours: parsedJson["${key}travel_hours"],
userName: parsedJson["${key}name"],
signature: parsedJson["${key}image"],
userId: parsedJson["${key}id"],
comment: parsedJson["${key}comment"],
assignedEmployeeName:parsedJson["${key}AssignedEmployeeName"],
assignedEmployeeName: parsedJson["${key}AssignedEmployeeName"],
client: Hospital(id: parsedJson["${key}SiteId"], name: parsedJson["${key}SiteName"]),
department: Department(
id: parsedJson["${key}DepartmentId"],

@ -6,6 +6,7 @@ class GasRefillDetails {
Lookup cylinderType;
double requestedQuantity;
double deliveredQuantity;
bool selectedForEditing;
GasRefillDetails({
this.type,
@ -13,6 +14,7 @@ class GasRefillDetails {
this.cylinderType,
this.requestedQuantity,
this.deliveredQuantity,
this.selectedForEditing,
});
bool validate() {

@ -1,6 +1,11 @@
import 'dart:typed_data';
import 'package:test_sa/models/gas_refill/gas_refill_details.dart';
import 'package:test_sa/models/lookup.dart';
import '../../controllers/api_routes/urls.dart';
import '../call_request_for_work_order_model.dart';
class GasRefillModel {
int id;
//String userId;
@ -9,8 +14,15 @@ class GasRefillModel {
Lookup status;
Lookup building;
Lookup floor;
Department department;
List<GasRefillDetails> details;
AssignedEmployee assignedEmployee;
String signatureNurse;
String signatureEngineer;
Uint8List localNurseSignature;
Uint8List localEngineerSignature;
DateTime startDate, endDate, expectedDate;
GasRefillModel({
this.id,
//this.userId,
@ -18,13 +30,27 @@ class GasRefillModel {
this.title,
this.status,
this.details,
this.building,
this.floor,
this.startDate,
this.endDate,
this.expectedDate,
this.department,
this.assignedEmployee,
this.signatureNurse,
this.signatureEngineer,
this.localEngineerSignature,
this.localNurseSignature,
});
bool validate() {
if (title == null) return false;
if (status == null) return false;
if (building == null) return false;
if (floor == null) return false;
// if (building == null) return false;
// if (floor == null) return false;
// if (department == null) return false;
// if (startDate == null) return false;
// if (endDate == null) return false;
if (details == null && details.isEmpty) return false;
return true;
}
@ -36,6 +62,17 @@ class GasRefillModel {
title = model.title;
status = Lookup.fromStatus(model.status);
details = model.details.map((e) => GasRefillDetails.fromDetails(e)).toList();
building = model.building;
floor = model.floor;
department = model.department;
startDate = model.startDate;
endDate = model.endDate;
expectedDate = model.expectedDate;
assignedEmployee = model.assignedEmployee;
localEngineerSignature = model.localEngineerSignature;
localNurseSignature = model.localNurseSignature;
signatureEngineer = model.signatureEngineer;
signatureNurse = model.signatureNurse;
}
factory GasRefillModel.fromJson(Map<String, dynamic> parsedJson) {
@ -49,8 +86,17 @@ class GasRefillModel {
//userId: parsedJson["uid"],
title: parsedJson["gazRefillNo"],
clientName: parsedJson["site"] == null ? null : parsedJson["site"]["custName"],
status: Lookup.fromJson(parsedJson["status"]),
status: Lookup.fromJson(parsedJson["status"] ?? {}),
details: details,
building: Lookup.fromJson(parsedJson["building"] ?? {}),
floor: Lookup.fromJson(parsedJson["floor"] ?? {}),
department: Department.fromJson(parsedJson["department"] ?? {}),
startDate: DateTime.tryParse(parsedJson['startDate'] ?? ""),
endDate: DateTime.tryParse(parsedJson['endDate'] ?? ""),
expectedDate: DateTime.tryParse(parsedJson['expectedDate'] ?? ""),
assignedEmployee: AssignedEmployee.fromJson(parsedJson['assignedEmployee'] ?? {}),
signatureEngineer: URLs.getFileUrl(parsedJson["engSignature"]),
signatureNurse: URLs.getFileUrl(parsedJson["nurseSignature"]),
);
}
}

@ -17,7 +17,7 @@ class Hospital {
if (parsedJson['buildings'] != null) {
buildings = [];
parsedJson['buildings'].forEach((v) {
buildings.add(new Buildings.fromJson(v));
buildings.add(Buildings.fromJson(v));
});
}
@ -78,20 +78,20 @@ class Buildings {
name = json['name'];
value = json['value'];
if (json['floors'] != null) {
floors = new List<Floors>();
floors = [];
json['floors'].forEach((v) {
floors.add(new Floors.fromJson(v));
floors.add(Floors.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['value'] = this.value;
if (this.floors != null) {
data['floors'] = this.floors.map((v) => v.toJson()).toList();
Map<String, dynamic> toJson({bool includeFloors = true}) {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
data['value'] = value;
if (floors != null && includeFloors) {
data['floors'] = floors.map((v) => v.toJson()).toList();
}
return data;
}
@ -110,20 +110,20 @@ class Floors {
name = json['name'];
value = json['value'];
if (json['departments'] != null) {
departments = new List<Departments>();
departments = [];
json['departments'].forEach((v) {
departments.add(new Departments.fromJson(v));
departments.add(Departments.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['value'] = this.value;
if (this.departments != null) {
data['departments'] = this.departments.map((v) => v.toJson()).toList();
Map<String, dynamic> toJson({bool includeDepartments = true}) {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
data['value'] = value;
if (departments != null && includeDepartments) {
data['departments'] = departments.map((v) => v.toJson()).toList();
}
return data;
}
@ -141,9 +141,9 @@ class Departments {
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}

@ -58,7 +58,7 @@ class Pentry {
Map<String, dynamic> toMap(int visitId) {
Map<String, dynamic> map = {};
map["visitStatusId"] = ppmVisitStatus?.id.toString();
//if(status != null) map["visitStatusId"] = status?.id.toString();
if (status != null) map["deviceStatusId"] = status?.id.toString();
if (travelingHours != null) map["travelingHours"] = travelingHours;
//if(imageFile != null) map["file_attachement"] = base64Encode(imageFile.readAsBytesSync());
map["actualDate"] = actualVisitDate.toIso8601String();
@ -73,7 +73,7 @@ class Pentry {
{"attachmentName": (imageFile.path.split("/").last + base64Encode(imageFile.readAsBytesSync()))}
];
}
map["travelingHours"] = travelingHours;
// if(contacts?.isNotEmpty == true) {
// for(int i = 0;i<contacts.length;i++){
// contacts[i].toMap().forEach((key, value) {
@ -117,7 +117,12 @@ class Pentry {
actualVisitDate: DateTime.tryParse(map["actualDate"] ?? ""),
expectedVisitDate: DateTime.tryParse(map["expectedDate"] ?? ""),
travelingHours: map["travelingHours"],
timer: TimerModel(startAt: DateTime.tryParse(map["startDate"] ?? ""), endAt: DateTime.tryParse(map["endDate"] ?? ""), durationInSecond: (int.tryParse(map["workingHours"] ?? "") ?? 0) * 60 * 60),
timer: TimerModel(
startAt: DateTime.tryParse(map["startDate"] ?? ""),
endAt: DateTime.tryParse(map["endDate"] ?? ""),
durationInSecond: (int.tryParse(map["workingHours"] ?? "") ?? 0) * 60 * 60,
stopped: map["workingHours"] == null ? null : true,
),
// contacts: contacts,
ppmCheckLists: ppmCheckLists,
calibrationTools: calibrationTools,

@ -1,5 +1,6 @@
import 'dart:typed_data';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/models/device/device.dart';
import 'package:test_sa/models/engineer.dart';
@ -13,10 +14,11 @@ class ServiceReport {
int id;
double operatingHours;
DateTime visitDate;
DateTime endDate;
DateTime startDate;
// DateTime endDate;
// DateTime startDate;
Lookup assetType;
Lookup callLastSituation;
Lookup currentSituation;
Lookup repairLocation;
Engineer engineer;
Lookup equipmentStatus;
@ -25,7 +27,7 @@ class ServiceReport {
int faultDescriptionId;
String workPreformed;
//String workHours;
num workingHours;
double travelingHours;
String invoiceNumber;
String invoiceCode;
@ -40,50 +42,52 @@ class ServiceReport {
String comment;
Uint8List localNurseSignature;
Uint8List localEngineerSignature;
int travelingExpense;
num travelingExpense;
String reviewComment;
FaultDescription faultDescription;
ServiceReport(
{this.id,
this.visitDate,
this.endDate,
this.assetType,
this.equipmentStatus,
this.type,
this.faultDescriptionId,
//this.workHours,
this.travelingHours,
this.parts,
this.engineer,
this.workPreformed,
this.reason,
this.operatingHours,
this.callLastSituation,
this.jobSheetNumber,
this.image,
this.device,
this.invoiceCode,
this.invoiceNumber,
this.quantity = "1",
this.timer,
this.signatureNurse,
this.signatureEngineer,
this.localNurseSignature,
this.localEngineerSignature,
this.comment,
this.repairLocation,
this.travelingExpense,
this.startDate,
this.reviewComment,
this.faultDescription});
ServiceReport({
this.id,
this.visitDate,
// this.endDate,
this.assetType,
this.equipmentStatus,
this.type,
this.faultDescriptionId,
this.workingHours,
this.travelingHours,
this.parts,
this.engineer,
this.workPreformed,
this.reason,
this.operatingHours,
this.callLastSituation,
this.currentSituation,
this.jobSheetNumber,
this.image,
this.device,
this.invoiceCode,
this.invoiceNumber,
this.quantity = "1",
this.timer,
this.signatureNurse,
this.signatureEngineer,
this.localNurseSignature,
this.localEngineerSignature,
this.comment,
this.repairLocation,
this.travelingExpense,
// this.startDate,
this.reviewComment,
this.faultDescription,
});
Map<String, dynamic> toMap(ServiceRequest request) {
Map<String, dynamic> _map = {};
if (id != null) _map["id"] = id;
if (visitDate != null) _map["visitDate"] = visitDate.toIso8601String();
//if(serviceType != null) _map["service_type"] = serviceType.id.toString();
if (equipmentStatus != null) _map["status"] = equipmentStatus?.toMap();
if (equipmentStatus != null) _map["equipmentStatus"] = equipmentStatus?.toMap();
if (type != null) _map["typeOfWO"] = type?.toMap();
if (assetType != null) _map["TypeOfWO"] = assetType?.toMap();
//if(faultDescriptionId != null && faultDescriptionId.isNotEmpty) _map["fault_description"] = faultDescriptionId;
@ -93,17 +97,19 @@ class ServiceReport {
_map["endofWorkTime"] = (timer.endAt ?? DateTime.now()).toIso8601String();
_map["workingHours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5);
}
if (travelingHours != null && travelingHours.toString().isNotEmpty) _map["traveling_hours"] = travelingHours;
if (travelingHours != null && travelingHours.toString().isNotEmpty) _map["travelingHours"] = travelingHours;
// if(workPreformed != null && workPreformed.isNotEmpty){
// _map["faultDescription"] = {
// //"id":faultDescriptionId ?? 0,
// "id":faultDescriptionId ?? 0,
// "workPerformed":workPreformed
// };
// }
if (travelingHours != null) _map["traveling_hours"] = travelingHours;
if (workPreformed != null && workPreformed.isNotEmpty) {
_map["faultDescription"] = faultDescription.toJson();
}
_map["faultDescription"] = {"id": faultDescription?.id ?? 0, "workPerformed": faultDescription?.workPerformed};
if (travelingHours != null) _map["travelingHours"] = travelingHours;
// if (workingHours != null) _map["workingHours"] = workingHours;
// if (workPreformed != null && workPreformed.isNotEmpty) {
// _map["faultDescription"] = faultDescription.toJson();
// }
if (jobSheetNumber != null && jobSheetNumber.isNotEmpty) _map["job_sheet_no"] = jobSheetNumber;
if (parts != null && parts.isNotEmpty) {
_map["sparePartsWorkOrders"] = parts.map((e) => e.toJson()).toList();
@ -122,6 +128,7 @@ class ServiceReport {
if (reason != null) _map["reason"] = reason.toMap();
//if(operatingHours != null && operatingHours.isNotEmpty) _map["operation_hours"] = operatingHours;
if (callLastSituation != null) _map["calllastSituation"] = callLastSituation.toMap();
if (currentSituation != null) _map["currentSituation"] = currentSituation.toMap();
//if(image != null) _map["image"] = image;
//if(invoiceCode != null) _map["invoice_no"] = invoiceCode;
//if(invoiceNumber != null) _map["invoice_code"] = invoiceNumber;
@ -133,16 +140,27 @@ class ServiceReport {
_map["nurseSignature"] = signatureNurse;
_map["engSignature"] = signatureEngineer;
_map["comment"] = comment;
_map["travelingExpense"] = travelingExpense;
_map["startofWorkTime"] = startDate;
_map["endofWorkTime"] = endDate;
_map["workingHours"] = endDate?.difference(startDate)?.inHours ?? 0;
_map["travelingExpenses"] = travelingExpense;
// _map["startofWorkTime"] = startDate.toIso8601String();
// _map["endofWorkTime"] = endDate.toIso8601String();
// _map["workingHours"] = endDate?.difference(startDate)?.inHours ?? 0;
if (timer?.startAt != null) _map["startofWorkTime"] = timer?.startAt?.toIso8601String();
if (timer?.endAt != null) _map["endofWorkTime"] = timer?.endAt?.toIso8601String();
_map["workingHours"] = workingHours;
_map["reviewComment"] = reviewComment;
return _map;
}
bool validate() {
if (visitDate == null) return false;
Future<bool> validate() async {
print("visitDate:$visitDate");
print("equipmentStatus:${equipmentStatus?.toMap()}");
print("callLastSituation:${callLastSituation?.toMap()}");
print("parts:$parts");
print("reason:${reason?.toMap()}");
if (visitDate == null) {
await Fluttertoast.showToast(msg: "Visit Date Required");
return false;
}
//if(serviceType == null) return false;
if (equipmentStatus == null) return false;
//if (type == null && assetType == null) return false;
@ -174,27 +192,38 @@ class ServiceReport {
id: id,
assetType: Lookup.fromJson(parsedJson["assetType"]),
callLastSituation: Lookup.fromJson(parsedJson["calllastSituation"]),
currentSituation: Lookup.fromJson(parsedJson["currentSituation"]),
repairLocation: Lookup.fromJson(parsedJson["repairLocation"]),
reason: Lookup.fromJson(parsedJson["reason"]),
equipmentStatus: Lookup.fromJson(parsedJson["status"]),
equipmentStatus: Lookup.fromJson(parsedJson["equipmentStatus"]),
type: Lookup.fromJson(parsedJson["typeOfWO"]),
faultDescriptionId: parsedJson["fault_description"],
endDate: DateTime.tryParse(parsedJson["endofWorkTime"]),
faultDescription: parsedJson['faultDescription'] != null ? FaultDescription.fromJson(parsedJson['faultDescription']) : null,
// faultDescription: parsedJson["faultDescription"],
// startDate: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""),
// endDate: DateTime.tryParse(parsedJson["endofWorkTime"] ?? ""),
//invoiceCode: parsedJson["invoice_code"],
//invoiceNumber: parsedJson["invoice_no"],
//jobSheetNumber: parsedJson["job_sheet_no"],
operatingHours: parsedJson["workingHours"],
// workingHours: parsedJson["workingHours"],
engineer: Engineer.fromJson(parsedJson["assignedEmployee"]),
parts: _parts,
//quantity: parsedJson["nid"],
travelingHours: parsedJson["traveling_hours"],
travelingHours: parsedJson["travelingHours"],
travelingExpense: parsedJson["travelingExpenses"],
visitDate: DateTime.tryParse(parsedJson["visitDate"]),
//workHours: parsedJson["working_hours"],
workingHours: parsedJson["workingHours"],
timer: TimerModel(
startAt: DateTime.tryParse(parsedJson["startofWorkTime"]), endAt: DateTime.tryParse(parsedJson["endofWorkTime"]), durationInSecond: ((parsedJson["workingHours"] ?? 0) * 60 * 60).toInt()),
startAt: DateTime.tryParse(parsedJson["startofWorkTime"] ?? ""),
endAt: DateTime.tryParse(parsedJson["endofWorkTime"] ?? ""),
durationInSecond: ((parsedJson["workingHours"] ?? 0) * 60 * 60).toInt(),
stopped: parsedJson["workingHours"] == null ? null : true,
),
//workPreformed: parsedJson["work_performed"],
device: Device.fromJson(parsedJson["callRequest"]["asset"]),
signatureNurse: URLs.getFileUrl(parsedJson["nurseSignature"]),
signatureEngineer: URLs.getFileUrl(parsedJson["engSignature"]),
comment: parsedJson['comment'],
reviewComment: parsedJson['reviewComment'],
);
}

File diff suppressed because it is too large Load Diff

@ -15,6 +15,7 @@ class ServiceRequest {
int hospitalId;
String departmentName;
String engineerName;
String engineerId;
String date;
String audio;
int statusValue;
@ -57,6 +58,7 @@ class ServiceRequest {
this.deviceId,
this.audio,
this.engineerName,
this.engineerId,
this.viewReport = false,
this.deviceModel,
this.engineerMobile,
@ -102,6 +104,7 @@ class ServiceRequest {
statusValue: parsedJson["status"] == null ? null : parsedJson["status"]["value"],
departmentName: parsedJson["asset"]["department"] != null ? parsedJson["asset"]["department"]["name"] : "",
engineerName: parsedJson["assignedEmployee"] == null ? null : parsedJson["assignedEmployee"]["name"],
engineerId: parsedJson["assignedEmployee"] == null ? null : parsedJson["assignedEmployee"]["id"],
hospitalId: parsedJson["asset"]["site"]["id"],
reportID: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workOrderId"] : null,
viewReport: parsedJson["workOrder"] != null,

@ -229,6 +229,8 @@ class Subtitle {
String travelingExpense;
String startDate;
String endDate;
String requestedQuantity;
String deliveredQuantity;
String destinationSite;
String building;
String floor;
@ -439,6 +441,8 @@ class Subtitle {
@required this.travelingExpense,
@required this.startDate,
@required this.endDate,
@required this.requestedQuantity,
@required this.deliveredQuantity,
@required this.assetNumber,
@required this.destinationSite,
@required this.building,
@ -643,6 +647,8 @@ class Subtitle {
travelingExpense: parsedJson["travelingExpense"],
startDate: parsedJson["startDate"],
endDate: parsedJson["endDate"],
requestedQuantity: parsedJson["requestedQuantity"],
deliveredQuantity: parsedJson["deliveredQuantity"],
destinationSite: parsedJson["destinationSite"],
building: parsedJson["building"],
floor: parsedJson["floor"],

@ -2,6 +2,7 @@ class TimerModel {
DateTime startAt;
DateTime endAt;
int durationInSecond;
bool stopped;
TimerModel({this.startAt, this.endAt, this.durationInSecond});
TimerModel({this.startAt, this.endAt, this.durationInSecond, this.stopped});
}

@ -86,11 +86,15 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RequestInfoRow(
title: _subtitle.title,
title: "Id",
info: widget.model.id?.toString(),
),
RequestInfoRow(
title: _subtitle.assetName,
info: widget.model.title,
),
RequestInfoRow(
title: _subtitle.device,
title: _subtitle.assetSN,
info: widget.model.device.serialNumber,
),
RequestInfoRow(

@ -19,8 +19,7 @@ import 'package:test_sa/views/widgets/status/gas_refill/gas_status.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../controllers/validator/validator.dart';
import '../../widgets/date_and_time/time_picker.dart';
import '../../widgets/timer/app_timer.dart';
class UpdateDeviceTransfer extends StatefulWidget {
final DeviceTransfer model;
@ -46,6 +45,13 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
_update() async {
if (_formModel?.workingHours == null || _formModel.workingHours.isEmpty) {
await Fluttertoast.showToast(msg: "Working Hours Timer Isn't Started");
return;
} else if ((_formModel?.timer?.stopped ?? false) == false) {
await Fluttertoast.showToast(msg: "Stop The Timer");
return;
}
_validate = true;
if (!_formKey.currentState.validate()) {
setState(() {});
@ -152,96 +158,23 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
const SizedBox(
height: 16,
),
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("Start of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _formModel.startDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_formModel.startDate = date;
_formModel.workingHours = ((_formModel.endDate?.difference(_formModel.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? 0;
setState(() {});
},
),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("End of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _formModel.endDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_formModel.endDate = date;
_formModel.workingHours = ((_formModel.endDate?.difference(_formModel.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? 0;
setState(() {});
},
),
],
child: AppTimer(
timer: _formModel.timer,
onChange: (timer) async {
_formModel.timer = timer;
_formModel.workingHours = (((timer?.durationInSecond ?? 0) / 60) / 60)?.toStringAsFixed(2) ?? "0";
return true;
},
),
),
],
),
const SizedBox(height: 4),
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 4),
ATextFormField(
initialValue: null,
textAlign: TextAlign.center,
hintText: _formModel.startDate == null ? "0" : ((_formModel.endDate?.difference(_formModel.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? "0",
enable: false,
style: Theme.of(context).textTheme.subtitle1,
//validator: (value) => Validator.isNumeric(value) ? null : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value) {
// _serviceReport.workHours = value;
},
),
// ASubTitle(_subtitle.workingHours),
// const SizedBox(
// height: 4,
// ),
// ATextFormField(
// initialValue: _formModel?.workingHours,
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.number,
// onSaved: (value) {
// _formModel.workingHours = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("Sender Department"),
// if(_validate && _formModel.senderDepartment == null)
// ASubTitle(_subtitle.requiredWord,color: Colors.red,),
// const SizedBox(height: 4,),
// DepartmentButton(
// department: _formModel.senderDepartment,
// onDepartmentPick: (department){
// _formModel.senderDepartment = department;
// setState(() {});
// },
// ),
const SizedBox(
height: 8,
),
const SizedBox(height: 16),
ASubTitle(_subtitle.status),
const SizedBox(
height: 4,
@ -249,6 +182,7 @@ class _UpdateDeviceTransferState extends State<UpdateDeviceTransfer> {
GasStatusMenu(
initialValue: _formModel.status,
onSelect: (status) {
if (status == null) return;
_formModel.status = status;
setState(() {});
},

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/localization/localization.dart';
@ -114,9 +115,16 @@ class _LoginState extends State<Login> {
host: _settingProvider.host,
);
if (status >= 200 && status < 300) {
_settingProvider.setUser(_userProvider.user);
if(_userProvider.user.isAuthenticated ?? false) {
_settingProvider.setUser(_userProvider.user);
Navigator.of(context).pushNamed(LandPage.id);
} else {
Fluttertoast.showToast(msg: _userProvider.user.message);
}
// if (_userProvider.user.isActive)
Navigator.of(context).pushNamed(LandPage.id);
// else
// Fluttertoast.showToast(msg: _subtitle.activationAlert);
} else {

@ -0,0 +1,363 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/call_request_for_work_order_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_report.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/pages/sub_workorder/spare_parts_details_bottom_sheet.dart';
import 'package:test_sa/views/pages/sub_workorder/work_order_details_bottom_sheet.dart';
import 'package:test_sa/views/pages/sub_workorder/workorder_details.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/status/service_request/service_request_defect_types_mune.dart';
import '../../../controllers/api_routes/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart';
import '../../../models/subtitle.dart';
import '../../widgets/app_text_form_field.dart';
import '../../widgets/buttons/app_back_button.dart';
import '../../widgets/buttons/app_button.dart';
import '../../widgets/date_and_time/date_picker.dart';
import '../../widgets/images/mini_one_image_picker.dart';
import '../../widgets/status/report/service_report_fault_description.dart';
import '../../widgets/status/report/service_report_reasons.dart';
import '../../widgets/titles/app_sub_title.dart';
class CreateSubWorkOrderPage extends StatefulWidget {
static const id = "/CreateSubWorkOrder";
final SearchWorkOrder workOrder;
const CreateSubWorkOrderPage({this.workOrder, Key key}) : super(key: key);
@override
State<CreateSubWorkOrderPage> createState() => _CreateSubWorkOrderPageState();
}
class _CreateSubWorkOrderPageState extends State<CreateSubWorkOrderPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
SearchWorkOrder _subWorkOrders;
Lookup _serviceReportReason = const Lookup();
ServiceReport _serviceReport;
File _image;
bool _isLoading = false;
bool _validate = false;
@override
void initState() {
_subWorkOrders = SearchWorkOrder(
assignedEmployee: widget?.workOrder?.callRequest?.assignedEmployee,
callRequest: CallRequest(id: widget?.workOrder?.callRequest?.id),
currentSituation: null,
supplier: null,
);
_serviceReport = ServiceReport(id: widget.workOrder.id, type: widget.workOrder.assetType, equipmentStatus: widget.workOrder.equipmentStatus);
_isLoading = true;
super.initState();
}
var assetTypesProvider;
CallRequestForWorkOrder _callRequestForWorkOrder;
Future getAssetType() async {
//if (assetTypesProvider == null) {
Provider.of<ServiceRequestFaultDescriptionProvider>(context, listen: false).reset();
assetTypesProvider = Provider.of<ServiceStatusProvider>(context, listen: false);
_callRequestForWorkOrder = await Provider.of<ServiceRequestsProvider>(context).getCallRequestForWorkOrder(callId: widget.workOrder.callRequest.id.toString());
await assetTypesProvider.getTypes();
_subWorkOrders?.assetType = assetTypesProvider.statuses?.firstWhere(
(element) => element.value == _callRequestForWorkOrder?.assetType,
orElse: () => null,
);
setState(() {
_isLoading = false;
});
//}
}
@override
Widget build(BuildContext context) {
if (_callRequestForWorkOrder == null) {
getAssetType();
}
final Subtitle subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
body: SafeArea(
child: _isLoading
? const ALoading()
: Column(
children: [
SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
"New Work Order",
style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(
width: 48,
)
],
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: Column(
children: [
WorkOrderDetails(item: widget.workOrder, assetType: _subWorkOrders?.assetType),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Equipment status"),
if (_validate && _subWorkOrders?.equipmentStatus == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
ServiceRequestDefectTypesMenu(
initialValue: _serviceReport.equipmentStatus,
onSelect: (status) {
_subWorkOrders.equipmentStatus = status;
_serviceReport.equipmentStatus = status;
setState(() {});
},
),
],
),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Return to Service"),
if (_validate && _subWorkOrders.visitDate == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
Row(
children: [
Expanded(
child: ADatePicker(
date: DateTime.tryParse(_subWorkOrders.visitDate ?? ""),
from: DateTime(1950),
onDatePicker: (date) {
_subWorkOrders.visitDate = date?.toIso8601String();
setState(() {});
},
),
),
],
),
],
),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle("Failure ${subtitle.reasons}"),
if (_validate && _subWorkOrders.reason == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
ServiceReportReasonsMenu(
initialValue: _serviceReportReason,
onSelect: (status) {
_serviceReportReason = status;
_subWorkOrders.reason = status;
setState(() {});
},
),
],
),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(subtitle.faultDescription),
if (_validate && _subWorkOrders.faultDescription == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
ServiceReportFaultDescription(
requestId: widget.workOrder?.callRequest?.id?.toString(),
initialValue: _subWorkOrders?.faultDescription,
onSelect: (status) {
_subWorkOrders.faultDescription = status;
if (mounted) setState(() {});
},
),
],
),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Solution"),
const SizedBox(height: 4),
ATextFormField(labelText: _subWorkOrders?.faultDescription?.workPerformed ?? "", textInputType: TextInputType.multiline, enable: false),
],
),
const SizedBox(height: 8),
InkWell(
onTap: () async {
await showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => WorkOrderDetailsBottomSheet(subWorkOrder: _subWorkOrders),
);
log(_subWorkOrders?.toJson()?.toString());
},
child: Card(
child: ListTile(
title: Row(
children: [
Text(
"WO Details",
style: Theme.of(context).textTheme.bodyMedium,
),
const Text("*", style: TextStyle(color: Colors.red)),
],
),
trailing: const Icon(Icons.arrow_forward_ios, size: 14, color: AColors.primaryColor),
),
),
),
const SizedBox(height: 8),
InkWell(
onTap: () async {
await showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => SparePartsBottomSheet(subWorkOrder: _subWorkOrders),
);
log(_subWorkOrders?.toJson()?.toString());
},
child: Card(
child: ListTile(
title: Row(
children: [
Text(
"Spare Parts",
style: Theme.of(context).textTheme.bodyMedium,
),
const Text("*", style: TextStyle(color: Colors.red)),
],
),
trailing: const Icon(Icons.arrow_forward_ios, size: 14, color: AColors.primaryColor),
),
),
),
const SizedBox(height: 8),
AMiniOneImagePicker(
image: _image,
onPick: (image) {
_image = image;
_subWorkOrders.attachmentsWorkOrder ??= [];
_subWorkOrders.attachmentsWorkOrder.add(AttachmentsWorkOrder(name: "${image.path.split("/").last}|${base64Encode(image.readAsBytesSync())}"));
},
),
const SizedBox(height: 50),
],
),
),
],
),
),
).expanded,
Padding(
padding: const EdgeInsets.all(16.0),
child: AButton(
text: subtitle.create,
onPressed: () async {
_subWorkOrders.parentWOId = widget.workOrder.id;
_validate = true;
setState(() {});
if (validate()) {
if (_subWorkOrders.timer?.startAt == null || _subWorkOrders.timer?.endAt == null) {
Fluttertoast.showToast(msg: "Working hours required");
return;
} else if (_subWorkOrders.calllastSituation == null) {
Fluttertoast.showToast(msg: "${subtitle.callLastSituation} required");
return;
}
_validate = false;
_isLoading = true;
setState(() {});
if (_formKey.currentState?.validate() ?? false) {}
_formKey.currentState?.save();
final serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false);
final status = await serviceRequestsProvider.createSubWorkOrder(workOrder: _subWorkOrders);
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {
Fluttertoast.showToast(msg: subtitle.requestCompleteSuccessfully);
Navigator.of(context).pop();
Navigator.of(context).pop();
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: serviceRequestsProvider.stateCode, subtitle: subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(errorMessage),
));
}
}
},
),
),
],
),
),
);
}
bool validate() {
if (_subWorkOrders.faultDescription == null || _subWorkOrders.reason == null || _subWorkOrders.equipmentStatus == null || _subWorkOrders.visitDate == null) {
return false;
} else {
return true;
}
}
}

@ -0,0 +1,226 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/models/engineer.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/pages/sub_workorder/workorder_list.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/hospitals/hospital_auto_complete_field_new.dart';
import '../../../controllers/api_routes/http_status_manger.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart';
import '../../app_style/colors.dart';
import '../../widgets/buttons/app_back_button.dart';
import '../../widgets/buttons/app_button.dart';
import '../../widgets/status/report/service_report_all_users.dart';
import '../../widgets/status/report/service_report_maintenance_situation.dart';
import '../../widgets/status/report/service_report_visit_date_operator.dart';
import '../../widgets/titles/app_sub_title.dart';
class SearchSubWorkOrderPage extends StatefulWidget {
static String id = "/SubWorkOrderPage";
const SearchSubWorkOrderPage({Key key}) : super(key: key);
@override
State<SearchSubWorkOrderPage> createState() => _SearchSubWorkOrderPageState();
}
class _SearchSubWorkOrderPageState extends State<SearchSubWorkOrderPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final SearchWorkOrder _searchWorkOrders = SearchWorkOrder();
Subtitle _subtitle;
bool _isLoading = false;
String _callerId = "", _site = "";
Lookup _dateOperator;
@override
void initState() {
super.initState();
if (context.mounted) {
Provider.of<ServiceReportMaintenanceSituationProvider>(context, listen: false).reset();
}
}
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
"Search Work Order",
style: Theme.of(context).textTheme.titleLarge.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(
width: 48,
)
],
),
],
),
),
const SizedBox(height: 8),
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ATextFormField(
labelText: "Caller ID",
onSaved: (value) {
_callerId = value;
},
),
const SizedBox(height: 16),
ATextFormField(
labelText: "Asset S.N.",
textInputType: TextInputType.number,
onSaved: (value) {
if (value != null) {
_searchWorkOrders.assetType = Lookup(name: value);
}
},
),
const SizedBox(height: 16),
ATextFormField(
labelText: "Work Order No.",
onSaved: (value) {
_searchWorkOrders.workOrderNo = value;
},
),
const SizedBox(height: 16),
ASubTitle(_subtitle.assignedEmployee),
const SizedBox(height: 4),
ServiceReportAllUsers(
initialValue: _searchWorkOrders.assignedEmployee == null ? null : Engineer(id: _searchWorkOrders.assignedEmployee.id, name: _searchWorkOrders.assignedEmployee.name),
onSelect: (engineer) {
_searchWorkOrders.assignedEmployee = AssignedEmployee(id: engineer.id, name: engineer.name);
},
),
const SizedBox(height: 16),
const ASubTitle("Maintenance Situation"),
const SizedBox(height: 4),
ServiceReportMaintenanceSituation(
initialValue: _searchWorkOrders.calllastSituation,
onSelect: (status) {
if (status?.value == 12 || _searchWorkOrders.calllastSituation?.value == 12) {
_searchWorkOrders.calllastSituation = status;
setState(() {});
} else {
_searchWorkOrders.calllastSituation = status;
}
},
woId: _searchWorkOrders.id?.toString(),
),
const SizedBox(height: 16),
HospitalAutoCompleteField(
initialValue:_site,
onSearch: (value) {
_site = value.name;
setState(() {
});
},
),
const SizedBox(height: 16),
ASubTitle(_subtitle.visitDate),
const SizedBox(height: 4),
ServiceReportVisitDateOperator(
initialValue: _dateOperator,
onSelect: (status) {
_dateOperator = status;
},
),
Row(
children: [
Expanded(
child: ADatePicker(
date: DateTime.tryParse(_searchWorkOrders.visitDate ?? ""),
from: DateTime(1950),
onDatePicker: (date) {
_searchWorkOrders.visitDate = date?.toIso8601String();
setState(() {});
},
),
),
],
),
],
),
),
),
const SizedBox(height: 100),
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: _isLoading
? const CircularProgressIndicator()
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: AButton(
text: _subtitle.search,
onPressed: () async {
_isLoading = true;
setState(() {});
if (_formKey.currentState?.validate() ?? false) {}
_formKey.currentState?.save();
final serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false);
serviceRequestsProvider.reset();
final List<SearchWorkOrder> woList = await serviceRequestsProvider.searchForWorkOrders(
_searchWorkOrders,
_callerId,
_dateOperator,
_site,
);
_isLoading = false;
setState(() {});
if (serviceRequestsProvider.stateCode >= 200 && serviceRequestsProvider.stateCode < 300) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WorkOrderList(
items: woList,
onLazyLoading: () async {
return await serviceRequestsProvider.searchForWorkOrders(
_searchWorkOrders,
_callerId,
_dateOperator,
_site,
);
},
),
),
);
} else {
String errorMessage = HttpStatusManger.getStatusMessage(status: serviceRequestsProvider.stateCode, subtitle: _subtitle);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(errorMessage)));
}
},
),
),
);
}
}

@ -0,0 +1,173 @@
import 'package:flutter/material.dart';
import 'package:test_sa/models/part.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/views/app_style/colors.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/subtitle.dart';
import '../../app_style/sizing.dart';
import '../../widgets/buttons/app_button.dart';
import '../../widgets/parts/auto_complete_parts_field.dart';
import '../../widgets/parts/part_item.dart';
import '../../widgets/titles/app_sub_title.dart';
class SparePartsBottomSheet extends StatefulWidget {
final SearchWorkOrder subWorkOrder;
const SparePartsBottomSheet({this.subWorkOrder, Key key}) : super(key: key);
@override
State<SparePartsBottomSheet> createState() => _SparePartsBottomSheetState();
}
class _SparePartsBottomSheetState extends State<SparePartsBottomSheet> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final SearchWorkOrder _workOrder = SearchWorkOrder();
bool _validate = false;
@override
void initState() {
super.initState();
_workOrder.copyFrom(widget.subWorkOrder);
}
@override
void dispose() {
_workOrder.sparePartsWorkOrders = widget.subWorkOrder.sparePartsWorkOrders;
super.dispose();
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final Subtitle subtitle = AppLocalization.of(context).subtitle;
return Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Container(
color: Colors.white,
height: size.height * 0.9,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("Spare Parts"),
const SizedBox(height: 8),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(color: AColors.grey, borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)), boxShadow: const [
BoxShadow(
color: AColors.grey,
offset: Offset(0, -1),
)
]),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(subtitle.partNumber),
_validate && _workOrder.sparePartsWorkOrders == null
? ASubTitle(
subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(height: 4),
AutoCompletePartsField(
onPick: (part) {
_workOrder.sparePartsWorkOrders ??= [];
_workOrder.sparePartsWorkOrders.add(SparePartsWorkOrders(
id: part.reportPartID,
qty: part.quantity,
sparePart: SparePart(id: part.id, partName: part.name, partNo: part.code),
));
},
),
],
),
),
],
),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
if (_workOrder.sparePartsWorkOrders?.isNotEmpty ?? false)
Row(
children: [
Expanded(flex: 3, child: Text(subtitle.number)),
Expanded(flex: 1, child: Text(subtitle.quantity)),
],
),
if (_workOrder.sparePartsWorkOrders?.isNotEmpty ?? false)
Column(
children: List.generate(
_workOrder.sparePartsWorkOrders?.length,
(index) {
final spare = _workOrder.sparePartsWorkOrders[index];
Part part = Part(
id: spare.sparePart?.id,
reportPartID: spare.id,
code: spare.sparePart?.partNo,
name: spare.sparePart?.partName,
quantity: spare.qty,
);
return PartItem(
part: part,
onEdit: (qty) {
spare.qty = qty;
},
onDelete: (part) {
_workOrder.sparePartsWorkOrders.remove(spare);
setState(() {});
},
);
},
),
),
const SizedBox(height: 16),
],
),
),
const SizedBox(height: 24),
],
),
),
),
),
AButton(
text: subtitle.submit,
onPressed: () async {
_formKey.currentState.save();
widget.subWorkOrder.copyFrom(_workOrder);
Navigator.pop(context);
},
),
],
),
),
),
),
);
}
}

@ -0,0 +1,176 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/status/report/service_report_assistant_employee_menu.dart';
import 'package:test_sa/views/widgets/status/report/service_report_maintenance_situation.dart';
import 'package:test_sa/views/widgets/status/report/service_report_repair_location.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart';
import '../../widgets/timer/app_timer.dart';
import '../../widgets/titles/app_sub_title.dart';
class WorkOrderDetailsBottomSheet extends StatefulWidget {
final SearchWorkOrder subWorkOrder;
const WorkOrderDetailsBottomSheet({this.subWorkOrder, Key key}) : super(key: key);
@override
State<WorkOrderDetailsBottomSheet> createState() => _WorkOrderDetailsBottomSheetState();
}
class _WorkOrderDetailsBottomSheetState extends State<WorkOrderDetailsBottomSheet> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final SearchWorkOrder _workOrder = SearchWorkOrder();
@override
void initState() {
super.initState();
_workOrder.copyFrom(widget.subWorkOrder);
if (context.mounted) {
Provider.of<ServiceReportMaintenanceSituationProvider>(context, listen: false).reset();
}
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final Subtitle subtitle = AppLocalization.of(context).subtitle;
return Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Container(
color: Colors.white,
height: size.height * 0.9,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ASubTitle("WO Details"),
const SizedBox(height: 8),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
ATextFormField(enable: false, hintText: "Assigned Employee: ${_workOrder.assignedEmployee?.name}"),
const SizedBox(height: 8),
const ASubTitle("Assistant Employee"),
const SizedBox(height: 4),
ServiceReportAssistantEmployeeMenu(
initialValue: (_workOrder.assistantEmployees?.isNotEmpty ?? false) ? _workOrder.assistantEmployees?.first : null,
onSelect: (assistantsEmployee) {
_workOrder.assistantEmployees = [assistantsEmployee];
},
),
const SizedBox(height: 8),
ASubTitle(subtitle.workingHours),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: AppTimer(
timer: _workOrder.timer,
onChange: (timer) async {
_workOrder.timer = timer;
_workOrder.workingHours = num.tryParse((((timer?.durationInSecond ?? 0) / 60) / 60)?.toStringAsFixed(2) ?? "0");
return true;
},
),
),
],
),
const SizedBox(height: 16),
ATextFormField(
labelText: "Travel Hours",
initialValue: _workOrder.travelingHours?.toString(),
textInputType: TextInputType.number,
onSaved: (value) {
_workOrder.travelingHours = num.tryParse(value);
},
),
const SizedBox(height: 8),
ATextFormField(
labelText: "Travel Expense",
initialValue: _workOrder.travelingExpenses?.toString(),
textInputType: TextInputType.number,
onSaved: (value) {
_workOrder.travelingExpenses = num.tryParse(value);
},
),
const SizedBox(height: 8),
ASubTitle(subtitle.callLastSituation),
const SizedBox(height: 4),
ServiceReportMaintenanceSituation(
initialValue: _workOrder.calllastSituation,
onSelect: (status) {
if (status?.value == 12 || _workOrder.calllastSituation?.value == 12) {
_workOrder.calllastSituation = status;
setState(() {});
} else {
_workOrder.calllastSituation = status;
}
},
woId: widget.subWorkOrder?.callRequest?.id?.toString(),
),
const SizedBox(height: 8),
const ASubTitle("Repair Location"),
const SizedBox(height: 4),
ServiceReportRepairLocation(
initialValue: _workOrder.repairLocation,
onSelect: (status) {
_workOrder.repairLocation = status;
},
),
const SizedBox(height: 8),
ATextFormField(
labelText: "Technical Comments",
initialValue: _workOrder.comment,
textInputType: TextInputType.multiline,
onSaved: (value) {
_workOrder.comment = value;
},
),
const SizedBox(height: 24),
],
),
),
),
),
AButton(
text: subtitle.submit,
onPressed: () async {
if (_workOrder?.workingHours == null) {
await Fluttertoast.showToast(msg: "Working Hours Timer Isn't Started");
return;
} else if ((_workOrder?.timer?.stopped ?? false) == false) {
await Fluttertoast.showToast(msg: "Stop The Timer");
return;
}
_formKey.currentState.save();
widget.subWorkOrder.copyFrom(_workOrder);
Navigator.pop(context);
},
),
],
),
),
),
),
);
}
}

@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'package:test_sa/models/lookup.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/subtitle.dart';
import '../../app_style/colors.dart';
import '../../app_style/sizing.dart';
class WorkOrderDetails extends StatelessWidget {
final SearchWorkOrder item;
Lookup assetType;
WorkOrderDetails({@required this.item, this.assetType, Key key}) : super(key: key);
Subtitle _subtitle;
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context).subtitle;
return Column(
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: const [
// AppStyle.boxShadow
// ]
),
child: Column(
children: [
_buildRow(_subtitle.callId, item.callRequest?.id?.toString() ?? "", context),
_buildRow(_subtitle.assetNumber, item.callRequest?.asset?.assetNumber ?? "", context),
_buildRow("WO No", item.workOrderNo, context),
_buildRow(_subtitle.assetName, item.callRequest?.asset?.assetNumber ?? '', context),
_buildRow(_subtitle.department, item.callRequest?.asset?.department ?? '', context),
_buildRow(_subtitle.assetSN, item.callRequest?.asset?.assetSerialNo ?? '', context),
_buildRow(_subtitle.model, item.callRequest?.asset?.modelDefinition?.modelName ?? "", context),
_buildRow("Manufacturer", item.callRequest?.asset?.modelDefinition?.manufacturerName ?? "", context),
_buildRow(_subtitle.site, item.callRequest?.asset?.site?.custName ?? "", context),
],
),
),
const SizedBox(height: 8),
Container(
padding: EdgeInsets.all(10),
height: 55,
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: _buildRow("Asset Type", assetType?.name ?? (item.assetType?.name ?? ""), context),
)
],
);
}
Widget _buildRow(String title, String value, BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
title + " : ",
style: Theme.of(context).textTheme.subtitle2.copyWith(fontWeight: FontWeight.bold),
),
//if (item.clientName != null)
Text(
value,
style: Theme.of(context).textTheme.subtitle2.copyWith(),
),
],
);
}
}

@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../../../models/service_request/search_work_order.dart';
class WorkOrderItem extends StatelessWidget {
final int index;
final SearchWorkOrder item;
final Function(SearchWorkOrder) onPressed;
const WorkOrderItem({Key key, this.item, this.onPressed, this.index}) : super(key: key);
@override
Widget build(BuildContext context) {
Subtitle _subtitle = AppLocalization.of(context).subtitle;
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
backgroundColor: itemColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
onPressed: () {
onPressed(item);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.callRequest.callNo ?? "-----",
style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
item.callRequest.asset.id.toString(),
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
Row(
children: [
Expanded(
child: Text(
_subtitle.assetName,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
),
//if (item.clientName != null)
Text(
item.callRequest.asset.assetNumber,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
],
),
Text(
item.calllastSituation.name,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
Divider(
color: onItemColor,
),
Row(
children: [
Expanded(
child: Text(
_subtitle.status,
style: Theme.of(context).textTheme.subtitle2.copyWith(
color: onItemColor,
),
),
),
if (item.callRequest.status?.id != null) StatusLabel(label: item.callRequest.status.name, color: AColors.getGasStatusColor(item.callRequest.status.id)),
],
),
],
),
),
],
),
],
),
),
);
}
}

@ -0,0 +1,101 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/views/pages/sub_workorder/workorder_item.dart';
import '../../../controllers/localization/localization.dart';
import '../../../controllers/providers/api/service_requests_provider.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/subtitle.dart';
import '../../app_style/colors.dart';
import '../../widgets/buttons/app_back_button.dart';
import '../../widgets/loaders/lazy_loading.dart';
import '../../widgets/loaders/no_item_found.dart';
import 'create_sub_workorder_page.dart';
class WorkOrderList extends StatefulWidget {
List<SearchWorkOrder> items;
final Future<List<SearchWorkOrder>> Function() onLazyLoading;
WorkOrderList({Key key, this.items, this.onLazyLoading}) : super(key: key);
@override
State<WorkOrderList> createState() => _WorkOrderListState();
}
class _WorkOrderListState extends State<WorkOrderList> {
List<SearchWorkOrder> _items;
@override
void initState() {
super.initState();
_items = widget.items;
}
@override
Widget build(BuildContext context) {
final serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context, listen: false);
Subtitle subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
body: SafeArea(
child: Column(
children: [
Container(
color: AColors.primaryColor,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Column(
children: [
Row(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
"Work Order List",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(width: 48),
],
),
],
),
),
Expanded(
child: _items?.isEmpty ?? []
? NoItemFound(
message: subtitle.noServiceRequestFound,
)
: LazyLoading(
nextPage: serviceRequestsProvider.nextPage,
onLazyLoad: () async {
_items = await widget.onLazyLoading();
setState(() {});
},
child: ListView.builder(
itemCount: _items.length,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemBuilder: (context, itemIndex) {
return WorkOrderItem(
index: itemIndex,
onPressed: (model) {
// Navigator.of(context).push(MaterialPageRoute(
// builder: (_) => WorkOrderUpdate(item: model,)));
log(model?.toJson()?.toString());
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CreateSubWorkOrderPage(workOrder: model)),
);
},
item: _items[itemIndex],
);
},
),
),
),
],
),
),
);
}
}

@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:test_sa/views/pages/sub_workorder/workorder_details.dart';
import '../../../controllers/localization/localization.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/subtitle.dart';
import '../../app_style/colors.dart';
import '../../widgets/buttons/app_back_button.dart';
import '../../widgets/loaders/loading_manager.dart';
class WorkOrderUpdate extends StatefulWidget {
final SearchWorkOrder item;
const WorkOrderUpdate({@required this.item, Key key}) : super(key: key);
@override
State<WorkOrderUpdate> createState() => _WorkOrderUpdateState();
}
class _WorkOrderUpdateState extends State<WorkOrderUpdate> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Subtitle _subtitle;
bool _isLoading = false;
@override
Widget build(BuildContext context) {
_subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
body: SafeArea(
child: Form(
key: _formKey,
child: LoadingManager(
isLoading: _isLoading,
isFailedLoading: false,
stateCode: 200,
onRefresh: () async {},
child: Column(
children: [
Container(
color: Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
child: Row(
children: [
const ABackButton(),
Expanded(
child: Center(
child: Text(
"Work Order",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white, fontStyle: FontStyle.italic),
),
),
),
const SizedBox(width: 58),
],
),
),
WorkOrderDetails(item: widget.item,)
],
),
),
),
),
);
}
}

@ -1,15 +1,16 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/http_status_manger.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/gas_refill_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/gas_refill/gas_refill_model.dart';
import 'package:test_sa/models/subtitle.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/buttons/app_icon_button.dart';
@ -20,6 +21,7 @@ import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/status/gas_refill/gas_status.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../models/enums/user_types.dart';
import '../../../app_style/colors.dart';
class GasRefillDetails extends StatefulWidget {
@ -109,14 +111,24 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
),
if (_userProvider.user.type == UsersTypes.engineer)
AIconButton(
iconData: _enableEdit ? Icons.cancel : Icons.edit,
iconData: /*_enableEdit ? Icons.cancel :*/ Icons.edit,
color: Theme.of(context).colorScheme.onPrimary,
buttonSize: 42,
backgroundColor: AColors.green,
onPressed: () async {
_enableEdit = !_enableEdit;
// _enableEdit = !_enableEdit;
print(widget.model.startDate);
_model.fromGasRefillModel(widget.model);
setState(() {});
print(widget.model.startDate);
// setState(() {});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RequestGasRefill(
gasRefillModel: widget.model,
),
),
);
},
),
const SizedBox(
@ -139,6 +151,22 @@ class _GasRefillDetailsState extends State<GasRefillDetails> {
title: _subtitle.hospital,
info: _model.clientName,
),
RequestInfoRow(
title: "Building",
info: _model.building?.name,
),
RequestInfoRow(
title: "Floor",
info: _model.floor?.name,
),
RequestInfoRow(
title: _subtitle.startDate,
info: _model.startDate == null ? null : DateFormat.yMd().format(_model.startDate),
),
RequestInfoRow(
title: _subtitle.endDate,
info: _model.endDate == null ? null : DateFormat.yMd().format(_model.endDate),
),
_enableEdit
? Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
@ -27,12 +29,14 @@ import 'package:test_sa/views/widgets/status/gas_refill/gas_type.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../controllers/localization/localization.dart';
import '../../../../controllers/providers/api/hospitals_provider.dart';
import '../../../../models/enums/user_types.dart';
import '../../../widgets/e_signature/e_signature.dart';
class RequestGasRefill extends StatefulWidget {
static const String id = "/request-gas-refill";
const RequestGasRefill({Key key}) : super(key: key);
final GasRefillModel gasRefillModel;
const RequestGasRefill({this.gasRefillModel, Key key}) : super(key: key);
@override
State<RequestGasRefill> createState() => _RequestGasRefillState();
@ -47,10 +51,20 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
GasRefillProvider _gasRefillProvider;
GasRefillDetails _currentDetails = GasRefillDetails();
final TextEditingController _requestedQuantityController = TextEditingController();
final GasRefillModel _formModel = GasRefillModel(details: []);
final TextEditingController _deliveredQuantityController = TextEditingController();
GasRefillModel _formModel = GasRefillModel(details: []);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey _DetailsKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
bool _firstTime = true;
@override
void initState() {
super.initState();
if (widget.gasRefillModel != null) {
_formModel = widget.gasRefillModel;
}
}
@override
void setState(VoidCallback fn) {
@ -64,12 +78,26 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_isLoading = true;
setState(() {});
if (widget.gasRefillModel != null) {
if (!_formModel.validate()) {
_isLoading = false;
setState(() {});
return;
}
}
int status = await _gasRefillProvider.createModel(
user: _userProvider.user,
host: _settingProvider.host,
model: _formModel,
);
int status = widget.gasRefillModel == null
? await _gasRefillProvider.createModel(
user: _userProvider.user,
host: _settingProvider.host,
model: _formModel,
)
: await _gasRefillProvider.updateModel(
user: _userProvider.user,
host: _settingProvider.host,
oldModel: widget.gasRefillModel,
newModel: _formModel,
);
_isLoading = false;
setState(() {});
if (status >= 200 && status < 300) {
@ -101,6 +129,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_validate = false;
Scrollable.ensureVisible(_DetailsKey.currentContext);
_requestedQuantityController.clear();
_deliveredQuantityController.clear();
_currentDetails = GasRefillDetails();
setState(() {});
return true;
@ -109,6 +138,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
@override
void dispose() {
_requestedQuantityController.dispose();
_deliveredQuantityController.dispose();
super.dispose();
}
@ -121,7 +151,22 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
_gasRefillProvider = Provider.of<GasRefillProvider>(context, listen: false);
_gasRefillProvider.reset();
}
if (widget.gasRefillModel != null && _firstTime) {
_formModel = widget.gasRefillModel;
_formModel.status = const Lookup(value: 0);
HospitalsProvider().getHospitalsListByVal(searchVal: widget.gasRefillModel.clientName).then((value) {
_gasRefillProvider.hospital = value?.firstWhere((element) => element.name == widget.gasRefillModel.clientName, orElse: () => null);
print(_gasRefillProvider.hospital?.buildings?.length);
print(widget.gasRefillModel?.building?.name);
_gasRefillProvider.building = _gasRefillProvider.hospital?.buildings?.firstWhere((element) => element.name == widget.gasRefillModel?.building?.name, orElse: () => null);
_gasRefillProvider.floor = _gasRefillProvider.building?.floors?.firstWhere((element) => element.name == widget.gasRefillModel?.floor?.name, orElse: () => null);
_gasRefillProvider.department = _gasRefillProvider.floor?.departments?.firstWhere((element) => element.name == widget.gasRefillModel?.department?.departmentName, orElse: () => null);
_gasRefillProvider.startDate = widget.gasRefillModel?.startDate;
_gasRefillProvider.endDate = widget.gasRefillModel?.endDate;
_firstTime = false;
setState(() {});
});
}
return Scaffold(
key: _scaffoldKey,
body: Form(
@ -141,7 +186,7 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Request Gas Refill",
"${widget.gasRefillModel == null ? "Request" : "Update"} Gas Refill",
style: Theme.of(context).textTheme.headline5.copyWith(color: Theme.of(context).primaryColor, fontSize: 28, fontWeight: FontWeight.bold),
),
),
@ -171,7 +216,8 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
height: 4,
),
GasStatusMenu(
initialValue: _formModel.status ?? const Lookup(value: 1),
initialValue: _formModel.status ?? const Lookup(value: 0),
enabled: false,
onSelect: (status) {
_formModel.status = status;
},
@ -247,149 +293,177 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
),
],
),
if (_userProvider.user?.type == UsersTypes.engineer)
Row(
// if (_userProvider.user?.type == UsersTypes.engineer)
// Column(
// children: [
// Row(
// children: [
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// const ASubTitle("Start of Work"),
// SizedBox(
// height: 8 * AppStyle.getScaleFactor(context),
// ),
// ADateTimePicker(
// date: _gasRefillProvider.startDate,
// from: DateTime.now().subtract(const Duration(days: 365)),
// to: DateTime.now().add(const Duration(days: 365)),
// onDateTimePicker: (date) {
// _gasRefillProvider.startDate = date;
// setState(() {});
// },
// ),
// ],
// ),
// ),
// const SizedBox(width: 8),
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// const ASubTitle("End of Work"),
// SizedBox(
// height: 8 * AppStyle.getScaleFactor(context),
// ),
// ADateTimePicker(
// date: _gasRefillProvider.endDate,
// from: DateTime.now().subtract(const Duration(days: 365)),
// to: DateTime.now().add(const Duration(days: 365)),
// onDateTimePicker: (date) {
// _gasRefillProvider.endDate = date;
// setState(() {});
// },
// ),
// ],
// ),
// ),
// ],
// ),
// const SizedBox(height: 8),
// ASubTitle(_subtitle.workingHours),
// const SizedBox(height: 4),
// ATextFormField(
// initialValue: null,
// textAlign: TextAlign.center,
// hintText: _gasRefillProvider.startDate == null
// ? "0"
// : ((_gasRefillProvider.endDate?.difference(_gasRefillProvider.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? "0",
// enable: false,
// style: Theme.of(context).textTheme.subtitle1,
// validator: (value) => Validator.isNumeric(value) ? null : _subtitle.requiredWord,
// textInputType: TextInputType.number,
// onSaved: (value) {
// // _serviceReport.workHours = value;
// },
// ),
// ],
// ),
if (widget.gasRefillModel == null)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("Start of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _gasRefillProvider.startDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_gasRefillProvider.startDate = date;
setState(() {});
},
),
],
const SizedBox(height: 8),
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 4),
const ASubTitle("Type"),
if (_validate && _currentDetails.type == null) ASubTitle(_subtitle.requiredWord, color: Colors.red),
const SizedBox(height: 4),
GasTypeMenu(
initialValue: _currentDetails.type,
onSelect: (status) {
_currentDetails.type = status;
},
),
const SizedBox(height: 8),
const ASubTitle("Cylinder Size"),
if (_validate && _currentDetails.cylinderSize == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasCylinderSizeMenu(
initialValue: _currentDetails.cylinderSize,
onSelect: (status) {
_currentDetails.cylinderSize = status;
},
),
const SizedBox(
height: 8,
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("End of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _gasRefillProvider.endDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_gasRefillProvider.endDate = date;
setState(() {});
},
),
],
const SizedBox(
height: 8,
),
const ASubTitle("Cylinder Type"),
if (_validate && _currentDetails.cylinderSize == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasCylinderTypesMenu(
initialValue: _currentDetails.cylinderType,
onSelect: (status) {
_currentDetails.cylinderType = status;
},
),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.requestedQuantity),
if (_validate && _currentDetails?.requestedQuantity == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
SizedBox(
height: 4,
),
ATextFormField(
initialValue: (_currentDetails?.requestedQuantity ?? "").toString(),
textAlign: TextAlign.center,
controller: _requestedQuantityController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
textInputType: TextInputType.number,
onChange: (value) {
_currentDetails?.requestedQuantity = double.tryParse(value);
},
),
if (widget.gasRefillModel != null) const SizedBox(height: 16),
if (widget.gasRefillModel != null) ASubTitle(_subtitle.deliveredQuantity),
if (widget.gasRefillModel != null && _validate && _currentDetails?.deliveredQuantity == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
if (widget.gasRefillModel != null) const SizedBox(height: 4),
if (widget.gasRefillModel != null)
ATextFormField(
initialValue: (_currentDetails?.deliveredQuantity ?? "").toString(),
textAlign: TextAlign.center,
controller: _deliveredQuantityController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
textInputType: TextInputType.number,
onChange: (value) {
_currentDetails?.deliveredQuantity = double.tryParse(value);
},
),
const SizedBox(height: 16),
AButton(
text: _subtitle.add,
onPressed: _addNewModel,
),
],
),
if (_userProvider.user?.type == UsersTypes.engineer) const SizedBox(height: 8),
if (_userProvider.user?.type == UsersTypes.engineer) ASubTitle(_subtitle.workingHours),
if (_userProvider.user?.type == UsersTypes.engineer) const SizedBox(height: 4),
if (_userProvider.user?.type == UsersTypes.engineer)
ATextFormField(
initialValue: null,
textAlign: TextAlign.center,
hintText: _gasRefillProvider.startDate == null
? "0"
: ((_gasRefillProvider.endDate?.difference(_gasRefillProvider.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? "0",
enable: false,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.isNumeric(value) ? null : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value) {
// _serviceReport.workHours = value;
},
),
const SizedBox(height: 8),
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 4),
const ASubTitle("Type"),
if (_validate && _currentDetails.type == null) ASubTitle(_subtitle.requiredWord, color: Colors.red),
const SizedBox(height: 4),
GasTypeMenu(
initialValue: _currentDetails.type,
onSelect: (status) {
_currentDetails.type = status;
},
),
const SizedBox(height: 8),
const ASubTitle("Cylinder Size"),
if (_validate && _currentDetails.cylinderSize == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasCylinderSizeMenu(
initialValue: _currentDetails.cylinderSize,
onSelect: (status) {
_currentDetails.cylinderSize = status;
},
),
const SizedBox(
height: 8,
),
const SizedBox(
height: 8,
),
const ASubTitle("Cylinder Type"),
if (_validate && _currentDetails.cylinderSize == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
GasCylinderTypesMenu(
initialValue: _currentDetails.cylinderType,
onSelect: (status) {
_currentDetails.cylinderType = status;
},
),
const SizedBox(
height: 8,
),
ASubTitle(_subtitle.quantity),
if (_validate && _currentDetails.requestedQuantity == null)
ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
),
SizedBox(
height: 4,
),
ATextFormField(
initialValue: (_currentDetails?.requestedQuantity ?? "").toString(),
textAlign: TextAlign.center,
controller: _requestedQuantityController,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
textInputType: TextInputType.number,
onSaved: (value) {
_currentDetails.requestedQuantity = double.tryParse(value);
},
),
const SizedBox(height: 16),
AButton(
text: _subtitle.add,
onPressed: _addNewModel,
),
if (_formModel.details.isNotEmpty) const ASubTitle("Gas Requests"),
ListView.builder(
key: _DetailsKey,
@ -399,21 +473,56 @@ class _RequestGasRefillState extends State<RequestGasRefill> {
itemBuilder: (context, index) {
final model = _formModel.details[index];
return GasRefillCreateDetailsItem(
isUpdate: widget.gasRefillModel != null,
model: model,
onDelete: () {
_formModel.details.remove(model);
onPressed: () {
if (widget.gasRefillModel != null) {
model.selectedForEditing = !(model.selectedForEditing ?? false);
}
if (widget.gasRefillModel == null) {
_formModel.details.remove(model);
}
setState(() {});
},
);
}),
if (widget.gasRefillModel != null) const SizedBox(height: 16),
if (widget.gasRefillModel != null) const ASubTitle("Nurse Signature"),
if (widget.gasRefillModel != null)
ESignature(
oldSignature: _formModel.signatureNurse,
newSignature: _formModel.localNurseSignature,
onChange: (signature) {
if (signature == null || signature.isEmpty) {
return;
}
_formModel.localNurseSignature = signature;
_formModel.signatureNurse = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
if (widget.gasRefillModel != null)
const SizedBox(
height: 8,
),
if (widget.gasRefillModel != null) const ASubTitle("Engineer Signature"),
if (widget.gasRefillModel != null)
ESignature(
oldSignature: _formModel.signatureEngineer,
newSignature: _formModel.localNurseSignature,
onChange: (signature) {
if (signature == null || signature.isEmpty) {
return;
}
_formModel.localNurseSignature = signature;
_formModel.signatureEngineer = "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}";
},
),
const SizedBox(height: 16),
AButton(
text: _subtitle.submit,
text: widget.gasRefillModel == null ? _subtitle.submit : _subtitle.update,
onPressed: _onSubmit,
),
const SizedBox(
height: 100,
)
const SizedBox(height: 100)
],
),
),

@ -26,7 +26,11 @@ class _TrackGasRefillPageState extends State<TrackGasRefillPage> with TickerProv
@override
Widget build(BuildContext context) {
_gasRefillProvider = Provider.of<GasRefillProvider>(context);
if (_gasRefillProvider == null) {
_gasRefillProvider = Provider.of<GasRefillProvider>(context);
//_gasRefillProvider?.isLoading = false;
_gasRefillProvider.reset();
}
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle _subtitle = AppLocalization.of(context).subtitle;

@ -23,6 +23,7 @@ import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart';
import 'package:test_sa/views/pages/device_transfer/track_device_transfer.dart';
import 'package:test_sa/views/pages/sub_workorder/search_sub_workorder_page.dart';
import 'package:test_sa/views/pages/user/gas_refill/request_gas_refill.dart';
import 'package:test_sa/views/pages/user/gas_refill/track_gas_refill.dart';
import 'package:test_sa/views/pages/user/requests/create_request.dart';
@ -211,6 +212,14 @@ class _LandPageState extends State<LandPage> {
Navigator.of(context).pushNamed(TrackDeviceTransferPage.id);
},
),
if (_userProvider?.user != null && _userProvider?.user?.type != UsersTypes.normal_user)
LandPageItem(
text: "Search Work Order",
svgPath: "assets/images/sub_workorder_icon.svg",
onPressed: () {
Navigator.of(context).pushNamed(SearchSubWorkOrderPage.id);
},
),
],
),
],

@ -306,7 +306,7 @@ class CreateRequestPageState extends State<CreateRequestPage> {
Fluttertoast.showToast(msg: _subtitle.pickDevice);
return;
}
if (_serviceRequest.firstAction != null && _dateTime == null) {
if (_serviceRequest.firstAction.name == "Need a visit" && _dateTime == null) {
Fluttertoast.showToast(msg: _subtitle.noDateFound);
return;
}

@ -23,24 +23,21 @@ import 'package:test_sa/views/widgets/app_text_form_field.dart';
import 'package:test_sa/views/widgets/buttons/app_back_button.dart';
import 'package:test_sa/views/widgets/buttons/app_button.dart';
import 'package:test_sa/views/widgets/date_and_time/date_picker.dart';
import 'package:test_sa/views/widgets/date_and_time/time_picker.dart';
import 'package:test_sa/views/widgets/e_signature/e_signature.dart';
import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart';
import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import 'package:test_sa/views/widgets/parts/part_item.dart';
import 'package:test_sa/views/widgets/status/employee/engineers_mune.dart';
import 'package:test_sa/views/widgets/status/report/service_report_equipment_status.dart';
import 'package:test_sa/views/widgets/status/report/service_report_last_call.dart';
import 'package:test_sa/views/widgets/status/report/service_report_reasons.dart';
import 'package:test_sa/views/widgets/status/report/service_report_status.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import '../../../../widgets/speech_to_text/speech_to_text.dart';
import '../../../../widgets/status/report/service_report_fault_description.dart';
import '../../../../widgets/status/report/service_report_repair_location.dart';
import '../../../../widgets/timer/app_timer.dart';
class CreateServiceReport extends StatefulWidget {
static final String id = "/create-service-report";
@ -331,7 +328,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ASubTitle(_subtitle.reportStatus),
// ASubTitle(_subtitle.reportStatus),
ASubTitle("Equipment Status"),
_validate && _serviceReport.equipmentStatus == null
? ASubTitle(
@ -418,71 +415,23 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("Start of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _serviceReport.startDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_serviceReport.startDate = date;
setState(() {});
},
),
],
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const ASubTitle("End of Work"),
SizedBox(
height: 8 * AppStyle.getScaleFactor(context),
),
ADateTimePicker(
date: _serviceReport.endDate,
from: DateTime.now().subtract(const Duration(days: 365)),
to: DateTime.now().add(const Duration(days: 365)),
onDateTimePicker: (date) {
_serviceReport.endDate = date;
setState(() {});
},
),
],
child: AppTimer(
timer: _serviceReport.timer,
onChange: (timer) async {
_serviceReport.timer = timer;
_serviceReport.workingHours = num.tryParse((((timer?.durationInSecond ?? 0) / 60) / 60)?.toStringAsFixed(2) ?? "0");
return true;
},
),
),
],
),
const SizedBox(height: 8),
ASubTitle(_subtitle.workingHours),
const SizedBox(height: 4),
ATextFormField(
initialValue: null,
textAlign: TextAlign.center,
hintText: _serviceReport.startDate == null
? "0"
: ((_serviceReport?.endDate?.difference(_serviceReport?.startDate)?.inMinutes ?? 0) / 60)?.toStringAsFixed(2)?.toString() ?? "0",
enable: false,
style: Theme.of(context).textTheme.subtitle1,
validator: (value) => Validator.isNumeric(value) ? null : _subtitle.requiredWord,
textInputType: TextInputType.number,
onSaved: (value) {
// _serviceReport.workHours = value;
},
),
const SizedBox(
height: 8,
),
const SizedBox(height: 16),
// device sn
Visibility(
visible: widget.request.deviceSerialNumber == null,
@ -636,7 +585,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
enable: false,
hintText: _serviceReport.faultDescription?.workPerformed ?? "",
controller: _workPreformedController,
style: Theme.of(context).textTheme.subtitle1,
style: Theme.of(context).textTheme.titleMedium,
validator: (value) => Validator.hasValue(value) ? null : _subtitle.requiredWord,
textInputType: TextInputType.multiline,
onSaved: (value) {
@ -656,6 +605,12 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ASubTitle(_subtitle.reasons),
_validate && _serviceReport.reason?.id == null
? ASubTitle(
_subtitle.requiredWord,
color: Colors.red,
)
: const SizedBox.shrink(),
const SizedBox(height: 4),
ServiceReportReasonsMenu(
initialValue: _serviceReport.reason,
@ -701,7 +656,7 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
ATextFormField(
initialValue: _serviceReport?.travelingExpense?.toString(),
hintText: _subtitle.travelingExpense,
hintText: "i.e 3, 3.5, 4",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
textInputType: TextInputType.number,
@ -929,9 +884,9 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
),
Column(
children: List.generate(_serviceReport.parts.length, (index) {
Part _part = _serviceReport.parts[index];
Part part = _serviceReport.parts[index];
return PartItem(
part: _part,
part: part,
onDelete: (part) {
_serviceReport.parts.remove(part);
setState(() {});
@ -955,7 +910,10 @@ class _CreateServiceReportState extends State<CreateServiceReport> with TickerPr
// setState(() {});
// return;
// }
if (!_serviceReport.validate()) return;
if (!(await _serviceReport.validate())) {
setState(() {});
return;
}
_formKey.currentState.save();
_isLoading = true;

@ -15,7 +15,7 @@ import 'edit_service_report.dart';
class FutureServiceReport extends StatefulWidget {
final ServiceRequest request;
final SearchWorkOrders workOrder;
final SearchWorkOrder workOrder;
const FutureServiceReport({Key key, this.request, this.workOrder}) : super(key: key);
@ -31,6 +31,8 @@ class _FutureServiceReportState extends State<FutureServiceReport> {
_userProvider = Provider.of<UserProvider>(context);
_settingProvider = Provider.of<SettingProvider>(context);
Subtitle _subtitle = AppLocalization.of(context).subtitle;
ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle)
;
return Scaffold(
body: FutureBuilder<ServiceReport>(
future: ServiceRequestsProvider().getSingleServiceReport(reportId: widget.workOrder.id, user: _userProvider.user, host: _settingProvider.host, subtitle: _subtitle),

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
@ -21,7 +20,6 @@ import 'package:test_sa/views/widgets/images/images_list.dart';
import 'package:test_sa/views/widgets/loaders/image_loader.dart';
import 'package:test_sa/views/widgets/requests/info_row.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/requests/service_request_update_dialog.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
@ -39,7 +37,7 @@ class RequestDetailsPage extends StatelessWidget {
Subtitle _subtitle = AppLocalization.of(context).subtitle;
UserProvider _userProvider = Provider.of<UserProvider>(context);
SettingProvider _settingProvider = Provider.of<SettingProvider>(context);
List<SearchWorkOrders> workOrders = [];
List<SearchWorkOrder> workOrders = [];
ServiceRequestsProvider _serviceRequestsProvider = Provider.of<ServiceRequestsProvider>(context);
return DefaultTabController(
length: 2,
@ -305,114 +303,135 @@ class RequestDetailsPage extends StatelessWidget {
FutureBuilder(
future: _serviceRequestsProvider.searchWorkOrders(callId: serviceRequest.requestCode),
builder: (context, snap) {
workOrders = snap.data as List<SearchWorkOrders>;
workOrders = snap.data as List<SearchWorkOrder>;
if (snap.connectionState == ConnectionState.waiting) return Center(child: CircularProgressIndicator());
if (snap.connectionState == ConnectionState.done && (snap.data?.length ?? 0) != 0) {
return ListView.separated(
padding: EdgeInsets.all(21),
itemCount: workOrders.length,
separatorBuilder: (czt, index) => 21.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return SingleChildScrollView(
child: Column(
children: [
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(21),
itemCount: workOrders.length,
separatorBuilder: (czt, index) => 21.height,
itemBuilder: (context, index) {
Color itemColor = index % 2 == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
Color onItemColor = index % 2 != 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onPrimary;
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor.withOpacity(.7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
primary: itemColor.withOpacity(.7),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppStyle.getBorderRadius(context)),
),
),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
onPressed: () {
// onPressed(request);
},
child: Column(
children: [
RequestInfoRow(
title: _subtitle.callId,
content: serviceRequest.requestCode,
),
RequestInfoRow(
title: _subtitle.orderWorkNumber,
info: workOrders[index].workOrderNo.toString(),
),
RequestInfoRow(
title: _subtitle.visitDate,
info: workOrders[index].visitDate,
),
RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee?.name??""),
RequestInfoRow(
title: _subtitle.assetSN,
info: workOrders[index].callRequest.asset.assetSerialNo,
),
RequestInfoRow(
title: _subtitle.assetName,
info: workOrders[index].callRequest.asset.modelDefinition.assetName,
),
RequestInfoRow(
title: _subtitle.model,
info: workOrders[index].callRequest.asset.modelDefinition.modelName,
),
RequestInfoRow(
title: _subtitle.site,
info: workOrders[index].callRequest.asset.site.custName,
),
RequestInfoRow(
title: _subtitle.maintenanceSituation,
info: workOrders[index].calllastSituation.name ?? '',
),
RequestInfoRow(
title: _subtitle.currentSituation,
info: workOrders[index].currentSituation.name ?? '',
),
_userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
},
),
)
: SizedBox.shrink(),
],
),
);
},
),
//padding: EdgeInsets.symmetric(vertical: 8,horizontal: 8),
onPressed: () {
// onPressed(request);
},
child: Column(
children: [
RequestInfoRow(
title: _subtitle.callId,
content: serviceRequest.requestCode,
),
RequestInfoRow(
title: _subtitle.orderWorkNumber,
info: workOrders[index].workOrderNo.toString(),
),
RequestInfoRow(
title: _subtitle.visitDate,
info: workOrders[index].visitDate,
),
RequestInfoRow(title: _subtitle.assignedEmployee, info: workOrders[index].assignedEmployee.name),
RequestInfoRow(
title: _subtitle.assetSN,
info: workOrders[index].callRequest.asset.assetSerialNo,
),
RequestInfoRow(
title: _subtitle.assetName,
info: workOrders[index].callRequest.asset.modelDefinition.assetName,
),
RequestInfoRow(
title: _subtitle.model,
info: workOrders[index].callRequest.asset.modelDefinition.modelName,
),
RequestInfoRow(
title: _subtitle.site,
info: workOrders[index].callRequest.asset.site.custName,
),
RequestInfoRow(
title: _subtitle.maintenanceSituation,
info: workOrders[index].calllastSituation.name ?? '',
),
RequestInfoRow(
title: _subtitle.currentSituation,
info: workOrders[index].currentSituation.name ?? '',
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Report",
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
_userProvider.user.type == UsersTypes.engineer && workOrders[index].workOrderNo != null
? Padding(
padding: EdgeInsets.all(32),
child: AButton(
text: _subtitle.editServiceReport,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FutureServiceReport(
request: serviceRequest,
workOrder: workOrders[index],
)),
);
},
),
)
: SizedBox.shrink(),
],
),
);
},
),
],
),
);
} else {
return _userProvider.user.type == UsersTypes.engineer
? Center(
return Column(
children: [
Expanded(
child: Center(
child: ASubTitle(_subtitle.dataNotFound),
),
),
if (_userProvider.user.type == UsersTypes.engineer)
Center(
child: Padding(
padding: EdgeInsets.all(32),
padding: const EdgeInsets.all(32),
child: AButton(
text: "Create Report",
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => CreateServiceReport(
request: serviceRequest,
)),
);
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CreateServiceReport(request: serviceRequest)));
},
),
),
)
: Center(
child: ASubTitle(_subtitle.noDateFound),
);
),
],
);
}
},
)
),
],
),
),

@ -44,11 +44,7 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPr
stateCode: _serviceRequestsProvider.stateCode,
onRefresh: () async {
_serviceRequestsProvider.reset();
await _serviceRequestsProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
hospitalId: _userProvider.user.clientId,
);
await _serviceRequestsProvider.getRequests(hospitalId: _userProvider.user.clientId);
},
child: Stack(
children: [
@ -104,11 +100,7 @@ class _ServiceRequestsPageState extends State<ServiceRequestsPage> with TickerPr
child: ServiceRequestsList(
nextPage: _serviceRequestsProvider.nextPage,
onLazyLoad: () async {
await _serviceRequestsProvider.getRequests(
user: _userProvider.user,
host: _settingProvider.host,
hospitalId: _userProvider.user.clientId,
);
await _serviceRequestsProvider.getRequests(hospitalId: _userProvider.user.clientId);
},
requests: _serviceRequestsProvider.serviceRequests,
),

@ -14,10 +14,11 @@ import 'package:test_sa/models/visits/visit.dart';
import 'package:test_sa/views/widgets/buttons/app_small_button.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/pentry/pentry_calibration_tool_form.dart';
import 'package:test_sa/views/widgets/pentry/pentry_info_form.dart';
import 'package:test_sa/views/widgets/pentry/pentry_pm_kit_form.dart';
import 'package:test_sa/views/widgets/pentry/pentry_ppm_check_list_form.dart';
import '../../../../widgets/pentry/pentry_info_form.dart';
class EditPentry extends StatefulWidget {
final Pentry pentry;
final Visit visit;
@ -73,7 +74,7 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
if (_pentry.pmKits.isEmpty) _pentry.pmKits.add(PMKit());
if (_pentry.calibrationTools.isEmpty) _pentry.calibrationTools.add(CalibrationTool());
if (_pentry.ppmCheckLists.isEmpty) _pentry.ppmCheckLists.add(PPMCheckList());
_tabController = TabController(length: 3, vsync: this);
_tabController = TabController(length: 4, vsync: this);
super.initState();
}
@ -104,25 +105,26 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
child: Padding(
padding: const EdgeInsets.all(2.0),
child: TabBar(
controller: _tabController,
isScrollable: true,
onTap: (index) {
setState(() {});
},
tabs: const [
Tab(
text: "PPM Check List",
),
// Tab(
// text: "Calibration Tools",
// ),
Tab(
text: "PK Kits",
),
Tab(
text: "Pentry",
),
]),
controller: _tabController,
isScrollable: true,
onTap: (index) {
setState(() {});
},
tabs: const [
Tab(
text: "PPM Check List",
),
Tab(
text: "Calibration Tools",
),
Tab(
text: "PM Kits",
),
Tab(
text: "PM Entry",
),
],
),
),
),
Expanded(
@ -147,7 +149,7 @@ class _EditPentryState extends State<EditPentry> with SingleTickerProviderStateM
PentryInfoForm(
model: _pentry,
enableValidate: _validate,
)
),
],
),
Align(

@ -21,7 +21,7 @@ class DeviceTransferInfoSection extends StatelessWidget {
info: info.client.name,
),
RequestInfoRow(
title: subtitle.unite,
title: subtitle.department,
info: info.department.name,
),
RequestInfoRow(

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
@ -53,6 +52,13 @@ class DeviceTransferItem extends StatelessWidget {
Divider(
color: onItemColor,
),
Text(
item.device?.number ?? "-----",
style: Theme.of(context).textTheme.headline6.copyWith(color: onItemColor, fontSize: 16, fontWeight: FontWeight.bold),
),
Divider(
color: onItemColor,
),
Row(
children: [
Expanded(

@ -27,12 +27,19 @@ class DeviceItem extends StatelessWidget {
},
child: ListTile(
title: Text(
"${_subtitle.sn} : ${device.serialNumber}",
"${_subtitle.assetName} : \n${device.modelDefinition.assetName}",
style: Theme.of(context).textTheme.headline6.copyWith(color: AColors.white),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
color: Theme.of(context).scaffoldBackgroundColor,
),
Text(
"${_subtitle.assetNumber} : ${device.number}",
style: Theme.of(context).textTheme.subtitle1.copyWith(color: AColors.white),
),
Divider(
color: Theme.of(context).scaffoldBackgroundColor,
),

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/devices_provider.dart';
@ -13,6 +12,7 @@ import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/loaders/no_item_found.dart';
import '../app_text_form_field.dart';
import '../qr/scan_qr.dart';
class SingleDevicePicker extends StatefulWidget {
static final String id = "/single-device-Picker";
@ -32,20 +32,20 @@ class _SingleDevicePickerState extends State<SingleDevicePicker> {
TextEditingController numberController = TextEditingController();
TextEditingController snController = TextEditingController();
_getDevice(String result) async {
print(result);
if (result == null) return;
showDialog(
barrierDismissible: false,
context: context,
builder: (dialogContext) {
return const Center(child: CircularProgressIndicator());
});
List<Device> devices = await _devicesProvider.getDevicesListBySN(host: _settingProvider.host, user: _userProvider.user, hospitalId: _userProvider.user.clientId, sn: result);
Navigator.of(context).pop();
if (devices.isEmpty) {
Fluttertoast.showToast(msg: _subtitle.noDeviceFound);
return;
}
Navigator.of(context).pop(devices.first);
// List<Device> devices = await _devicesProvider.getDevicesListBySN(host: _settingProvider.host, user: _userProvider.user, hospitalId: _userProvider.user.clientId, sn: result);
_devicesProvider.reset();
await _devicesProvider.getEquipment(user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: "", number: result);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
// Navigator.of(context).pop();
// Navigator.of(context).pop();
// if (devices.isEmpty) {
// Fluttertoast.showToast(msg: _subtitle.noDeviceFound);
// return;
// }
// Navigator.of(context).pop(devices.first);
}
@override
@ -73,93 +73,95 @@ class _SingleDevicePickerState extends State<SingleDevicePicker> {
_subtitle = AppLocalization.of(context).subtitle;
return Scaffold(
resizeToAvoidBottomInset: false,
body: LoadingManager(
isLoading: _devicesProvider.isLoading,
stateCode: _devicesProvider.stateCode,
isFailedLoading: _devicesProvider.devices == null,
onRefresh: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId);
},
child: Column(
children: [
const SizedBox(height: 48),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Column(
children: [
ATextFormField(
hintText: _subtitle.searchBySn,
controller: snController,
style: Theme.of(context).textTheme.subtitle1,
suffixIcon: const Icon(Icons.search_rounded),
textInputAction: TextInputAction.search,
onAction: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
},
),
const SizedBox(
height: 8,
),
ATextFormField(
hintText: "Search by Number",
controller: numberController,
style: Theme.of(context).textTheme.subtitle1,
suffixIcon: const Icon(Icons.search_rounded),
textInputAction: TextInputAction.search,
onAction: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
},
),
],
body: SafeArea(
child: LoadingManager(
isLoading: _devicesProvider.isLoading,
stateCode: _devicesProvider.stateCode,
isFailedLoading: _devicesProvider.devices == null,
onRefresh: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId);
},
child: Column(
children: [
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Column(
children: [
ATextFormField(
hintText: _subtitle.searchBySn,
controller: snController,
style: Theme.of(context).textTheme.subtitle1,
suffixIcon: const Icon(Icons.search_rounded),
textInputAction: TextInputAction.search,
onAction: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
},
),
const SizedBox(
height: 8,
),
ATextFormField(
hintText: "Search by Number",
controller: numberController,
style: Theme.of(context).textTheme.subtitle1,
suffixIcon: const Icon(Icons.search_rounded),
textInputAction: TextInputAction.search,
onAction: () async {
_devicesProvider.reset();
await _devicesProvider.getEquipment(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
},
),
],
),
),
),
Expanded(
child: _searchableList.isEmpty
? NoItemFound(
message: _subtitle.noDeviceFound,
)
: LazyLoading(
nextPage: _devicesProvider.nextPage,
onLazyLoad: () async {
await _devicesProvider.getDevicesList(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
},
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: _searchableList.length,
itemBuilder: (listContext, itemIndex) {
return DeviceItem(
device: _searchableList[itemIndex],
onPressed: (device) {
Navigator.of(context).pop(device);
},
);
Expanded(
child: _searchableList.isEmpty
? NoItemFound(
message: _subtitle.noDeviceFound,
)
: LazyLoading(
nextPage: _devicesProvider.nextPage,
onLazyLoad: () async {
await _devicesProvider.getDevicesList(
user: _userProvider.user, host: _settingProvider.host, hospitalId: _userProvider.user.clientId, serialNumber: snController.text, number: numberController.text);
},
),
)),
],
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: _searchableList.length,
itemBuilder: (listContext, itemIndex) {
return DeviceItem(
device: _searchableList[itemIndex],
onPressed: (device) {
Navigator.of(context).pop(device);
},
);
},
),
)),
],
),
),
),
// floatingActionButton: FloatingActionButton(
// heroTag: "some tag 2",
// child: const Icon(Icons.qr_code_scanner),
// onPressed: () async {
// String result = await Navigator.of(context).push(
// MaterialPageRoute(builder: (_)=> const ScanQr()),
// ) as String;
// _getDevice(result);
// },
// ),
floatingActionButton: FloatingActionButton(
heroTag: "some tag 2",
child: const Icon(Icons.qr_code_scanner),
onPressed: () async {
String result = await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ScanQr()),
) as String;
_getDevice(result);
},
),
);
}
}

@ -1,15 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class BuildingTypeMenu extends StatefulWidget {
final Function(Buildings) onSelect;
@ -41,6 +33,9 @@ class _BuildingTypeMenuState extends State<BuildingTypeMenu> {
_building = widget.building;
_selectedBuilding = null;
}
if (oldWidget.initialValue != widget.initialValue && widget.initialValue != null) {
_selectedBuilding = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}

@ -1,15 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class DepartmentTypeMenu extends StatefulWidget {
final Function(Departments) onSelect;
@ -41,6 +33,9 @@ class _DepartmentTypeMenuState extends State<DepartmentTypeMenu> {
_departments = widget.departments;
_selected = null;
}
if (oldWidget.initialValue != widget.initialValue && widget.initialValue != null) {
_selected = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}

@ -1,15 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/gas_refill/gas_types_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/models/hospital.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class FloorTypeMenu extends StatefulWidget {
final Function(Floors) onSelect;
@ -41,6 +33,9 @@ class _FloorTypeMenuState extends State<FloorTypeMenu> {
_floors = widget.floors;
_selected = null;
}
if (oldWidget.initialValue != widget.initialValue && widget.initialValue != null) {
_selected = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}

@ -1,38 +1,92 @@
import 'package:flutter/material.dart';
import 'package:test_sa/models/gas_refill/gas_refill_details.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/widgets/app_text_form_field.dart';
class GasRefillCreateDetailsItem extends StatelessWidget {
import '../../../controllers/localization/localization.dart';
import '../buttons/app_button.dart';
import '../titles/app_sub_title.dart';
class GasRefillCreateDetailsItem extends StatefulWidget {
final GasRefillDetails model;
final VoidCallback onDelete;
final VoidCallback onPressed;
final bool isUpdate;
const GasRefillCreateDetailsItem({Key key, this.isUpdate, this.model, this.onPressed}) : super(key: key);
@override
State<GasRefillCreateDetailsItem> createState() => _GasRefillCreateDetailsItemState();
}
const GasRefillCreateDetailsItem({Key key, this.model, this.onDelete}) : super(key: key);
class _GasRefillCreateDetailsItemState extends State<GasRefillCreateDetailsItem> {
GlobalKey<FormState> _formKey;
@override
void initState() {
super.initState();
_formKey = GlobalKey<FormState>();
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [Expanded(child: Text(model.type.name)), IconButton(onPressed: onDelete, color: AColors.red, icon: const Icon(Icons.delete))],
),
Wrap(
spacing: 10,
children: [
Text("Quantity: ${model.requestedQuantity.toStringAsFixed(0)}"),
Text("Cylinder Size: ${model.cylinderSize.name}"),
Text("Cylinder Type: ${model.cylinderType.name}"),
],
),
if (model.deliveredQuantity != null)
final subtitle = AppLocalization.of(context).subtitle;
final startEditing = widget.isUpdate && (widget.model.selectedForEditing ?? false);
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Text("Delivered Quantity"),
Text(model.deliveredQuantity.toStringAsFixed(0)),
Expanded(child: Text(widget.model.type.name)),
IconButton(onPressed: widget.onPressed, color: widget.isUpdate ? AColors.cyan : AColors.red, icon: Icon(widget.isUpdate ? Icons.edit : Icons.delete))
],
),
Wrap(
spacing: 10,
children: [
Text("Quantity: ${widget.model.requestedQuantity.toStringAsFixed(0)}"),
Text("Cylinder Size: ${widget.model.cylinderSize.name}"),
Text("Cylinder Type: ${widget.model.cylinderType.name}"),
],
),
const Divider(),
],
if (widget.model.deliveredQuantity != null)
Row(
children: [
const Text("Delivered Quantity: "),
Text(widget.model.deliveredQuantity.toStringAsFixed(0)),
],
),
if (startEditing) const SizedBox(height: 16),
if (startEditing) ASubTitle(subtitle.deliveredQuantity),
if (startEditing) const SizedBox(height: 4),
if (startEditing)
ATextFormField(
initialValue: widget.model.deliveredQuantity?.toString() ?? "0",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
// validator: (value) => Validator.isNumeric(value) ? null : "allow numbers only",
textInputType: TextInputType.number,
onSaved: (value) {
if (value.isNotEmpty) {
widget.model.deliveredQuantity = double.tryParse(value);
} else {
widget.model.deliveredQuantity = 0;
}
},
),
if (startEditing) const SizedBox(height: 8),
if (startEditing)
AButton(
text: subtitle.edit,
onPressed: () {
_formKey.currentState?.save();
widget.onPressed();
},
),
const Divider(),
],
),
);
}
}

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
@ -6,8 +7,8 @@ class LandPageItem extends StatelessWidget {
final String text;
final IconData icon;
final VoidCallback onPressed;
const LandPageItem({Key key, this.text, this.icon, this.onPressed}) : super(key: key);
final String svgPath;
const LandPageItem({Key key, this.svgPath, this.text, this.icon, this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -30,12 +31,20 @@ class LandPageItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(
icon,
color: AColors.primaryColor,
size: 42 * AppStyle.getScaleFactor(context),
),
Text(text, style: TextStyle(color: AColors.grey3A)),
if (icon != null)
Icon(
icon,
color: AColors.primaryColor,
size: 42 * AppStyle.getScaleFactor(context),
),
if (svgPath != null)
SvgPicture.asset(
svgPath,
width: 42 * AppStyle.getScaleFactor(context),
height: 42 * AppStyle.getScaleFactor(context),
color: AColors.primaryColor,
),
Text(text, style: const TextStyle(color: AColors.grey3A)),
],
),
),

@ -6,8 +6,9 @@ import 'package:test_sa/views/widgets/buttons/app_icon_button2.dart';
class PartItem extends StatefulWidget {
final Part part;
final Function(Part) onDelete;
final Function(int qty) onEdit;
const PartItem({Key key, this.part, this.onDelete}) : super(key: key);
const PartItem({Key key, this.part, this.onEdit, this.onDelete}) : super(key: key);
@override
_PartItemState createState() => _PartItemState();
@ -19,64 +20,73 @@ class _PartItemState extends State<PartItem> {
//final _subtitle = AppLocalization.of(context).subtitle;
return Column(
children: [
Divider(),
const Divider(),
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
widget.part.code,
style: Theme.of(context).textTheme.bodyText1.copyWith(fontSize: 12, fontWeight: FontWeight.bold),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
widget?.part?.code ?? "",
style: Theme.of(context).textTheme.bodyText1.copyWith(fontSize: 12, fontWeight: FontWeight.bold),
),
),
),
AIconButton2(
iconData: Icons.add,
color: Theme.of(context).primaryColor,
onPressed: () {
widget.part.quantity++;
setState(() {});
},
),
AIconButton2(
iconData: Icons.remove,
color: Theme.of(context).primaryColor,
onPressed: widget.part.quantity < 2
? null
: () {
widget.part.quantity--;
setState(() {});
},
),
SizedBox(
width: 8 * AppStyle.getScaleFactor(context),
),
Text(
widget.part.quantity.toString(),
style: Theme.of(context).textTheme.headline6.copyWith(
//fontSize: 12,
//fontWeight: FontWeight.bold
),
),
SizedBox(
width: 8 * AppStyle.getScaleFactor(context),
),
],
),
widget.part.name == null
? SizedBox.shrink()
: Text(
widget.part.name,
style: Theme.of(context).textTheme.caption.copyWith(fontSize: 11, fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
AIconButton2(
iconData: Icons.add,
color: Theme.of(context).primaryColor,
onPressed: () {
if (widget.onEdit == null) {
++widget.part.quantity;
} else {
widget.onEdit(++widget.part.quantity);
}
setState(() {});
},
),
],
)),
AIconButton2(
iconData: Icons.remove,
color: Theme.of(context).primaryColor,
onPressed: widget.part.quantity < 2
? null
: () {
if (widget.onEdit == null) {
--widget.part.quantity;
} else {
widget.onEdit(--widget.part.quantity);
}
setState(() {});
},
),
SizedBox(
width: 8 * AppStyle.getScaleFactor(context),
),
Text(
widget.part.quantity.toString(),
style: Theme.of(context).textTheme.headline6.copyWith(
//fontSize: 12,
//fontWeight: FontWeight.bold
),
),
SizedBox(
width: 8 * AppStyle.getScaleFactor(context),
),
],
),
widget.part.name == null
? const SizedBox.shrink()
: Text(
widget.part.name,
style: Theme.of(context).textTheme.caption.copyWith(fontSize: 11, fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
AIconButton2(
iconData: Icons.close,
color: Colors.red,

@ -43,9 +43,8 @@ class _PentryCalibrationToolFormState extends State<PentryCalibrationToolForm> {
);
}
final model = widget.models[index];
return ListView(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

@ -1,7 +1,6 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/localization/localization.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
@ -15,6 +14,8 @@ import 'package:test_sa/views/widgets/status/pentry/pentry_visit_status_mune.dar
import 'package:test_sa/views/widgets/timer/app_timer.dart';
import 'package:test_sa/views/widgets/titles/app_sub_title.dart';
import '../status/pentry/pentry_status_mune.dart';
class PentryInfoForm extends StatefulWidget {
final Pentry model;
final bool enableValidate;
@ -79,16 +80,21 @@ class _PentryInfoFormState extends State<PentryInfoForm> {
const SizedBox(
height: 8,
),
// const ASubTitle("Status"),
// // if(widget.enableValidate && widget.model.status == null)
// // ASubTitle(subtitle.requiredWord,color: Colors.red,),
// const SizedBox(height: 4,),
// PentryStatusMenu(
// initialValue: widget.model.status,
// onSelect: (status){
// widget.model.status = status;
// },
// ),
const ASubTitle("Status"),
if (widget.enableValidate && widget.model.status == null)
ASubTitle(
subtitle.requiredWord,
color: Colors.red,
),
const SizedBox(
height: 4,
),
PentryStatusMenu(
initialValue: widget.model.status,
onSelect: (status) {
widget.model.status = status;
},
),
const SizedBox(
height: 8,
),

@ -26,133 +26,66 @@ class _PentryPMKitFormState extends State<PentryPMKitForm> {
Widget build(BuildContext context) {
final subtitle = AppLocalization.of(context).subtitle;
return ListView.builder(
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context), left: 12 * AppStyle.getScaleFactor(context), right: 12 * AppStyle.getScaleFactor(context), bottom: 80 * AppStyle.getScaleFactor(context)),
itemCount: widget.models.length + 1,
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AButton(
text: subtitle.add,
onPressed: () {
widget.models.add(PMKit());
setState(() {});
},
);
}
final model = widget.models[index];
return ListView(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ASubTitle("#${index + 1}"),
if (index != 0)
ASmallButton(
color: Theme.of(context).colorScheme.error,
text: subtitle.delete,
onPressed: () {
widget.models.remove(model);
setState(() {});
},
),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Item Code"),
const SizedBox(
height: 4,
),
AutoCompletePartsField(
clearAfterPick: false,
initialValue: (model.itemCode?.name ?? "").toString(),
onPick: (part) {
model.itemCode = Lookup(id: part.id, name: part.code);
},
),
const SizedBox(
height: 8,
),
// const ASubTitle("Item Name"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.itemName ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.text,
// onChange: (value){
// model.itemName = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("Preparation Time Frame"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.preparationTimeFrame ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.text,
// onChange: (value){
// model.preparationTimeFrame = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("kit Frequency Demand"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.kitFrequencyDemand ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.text,
// onChange: (value){
// model.kitFrequencyDemand = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("Availability"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.availability ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.text,
// onChange: (value){
// model.availability = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("Quantity Needed"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.quantityNeeded ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.number,
// onChange: (value){
// model.quantityNeeded = value;
// },
// ),
// const SizedBox(height: 8,),
// const ASubTitle("Quantity Reserved"),
// const SizedBox(height: 4,),
// ATextFormField(
// initialValue: (model.quantityReserved ?? "").toString(),
// textAlign: TextAlign.center,
// style: Theme.of(context).textTheme.subtitle1,
// textInputType: TextInputType.number,
// onChange: (value){
// model.quantityReserved = value;
// },
// ),
// const SizedBox(height: 8,),
Divider(
color: Theme.of(context).textTheme.titleMedium.color,
),
],
padding: EdgeInsets.only(
top: 12 * AppStyle.getScaleFactor(context),
left: 12 * AppStyle.getScaleFactor(context),
right: 12 * AppStyle.getScaleFactor(context),
bottom: 100 * AppStyle.getScaleFactor(context) + MediaQuery.of(context).padding.bottom,
),
itemCount: widget.models.length + 1,
shrinkWrap: true,
itemBuilder: (context, index) {
if (index == widget.models.length) {
return AButton(
text: subtitle.add,
onPressed: () {
widget.models.add(PMKit());
setState(() {});
},
);
});
}
final model = widget.models[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ASubTitle("#${index + 1}"),
if (index != 0)
ASmallButton(
color: Theme.of(context).colorScheme.error,
text: subtitle.delete,
onPressed: () {
widget.models.remove(model);
setState(() {});
},
),
],
),
const SizedBox(
height: 8,
),
const ASubTitle("Item Code"),
const SizedBox(
height: 4,
),
AutoCompletePartsField(
clearAfterPick: false,
initialValue: (model.itemCode?.name ?? "").toString(),
onPick: (part) {
model.itemCode = Lookup(id: part.id, name: part.code);
},
),
const SizedBox(
height: 8,
),
Divider(
color: Theme.of(context).textTheme.titleMedium.color,
),
],
);
},
);
}
}

@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../models/service_request/search_work_order.dart';
class AssistantEmployeeMenu extends StatefulWidget {
final List<AssistantEmployees> statuses;
final AssistantEmployees initialStatus;
final Function(AssistantEmployees) onSelect;
const AssistantEmployeeMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key);
@override
_SingleAssistantEmployeeMenuState createState() => _SingleAssistantEmployeeMenuState();
}
class _SingleAssistantEmployeeMenuState extends State<AssistantEmployeeMenu> {
AssistantEmployees _selectedStatus;
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(fn);
}
@override
void didUpdateWidget(covariant AssistantEmployeeMenu oldWidget) {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element?.user?.id == widget.initialStatus?.user?.id;
});
if (result.isNotEmpty) {
_selectedStatus = result.first;
} else {
_selectedStatus = null;
}
if ((widget.initialStatus?.user?.id ?? "") != (_selectedStatus?.user?.id ?? "")) {
widget.onSelect(_selectedStatus);
}
} else {
_selectedStatus = null;
}
super.didUpdateWidget(oldWidget);
}
@override
void initState() {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element?.user?.id == widget.initialStatus?.user?.id;
});
if (result.isNotEmpty) _selectedStatus = result.first;
if (widget.initialStatus?.user?.id != _selectedStatus?.user?.id) {
widget.onSelect(_selectedStatus);
}
}
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: const [
// AppStyle.boxShadow
// ]
),
child: DropdownButton<AssistantEmployees>(
value: _selectedStatus,
iconSize: 24,
icon: const Icon(Icons.keyboard_arrow_down_rounded),
elevation: 0,
isExpanded: true,
hint: Text(
"Select",
style: Theme.of(context).textTheme.subtitle1,
),
style: TextStyle(color: Theme.of(context).primaryColor),
underline: const SizedBox.shrink(),
onChanged: (AssistantEmployees newValue) {
setState(() {
_selectedStatus = newValue;
});
widget.onSelect(newValue);
},
items: widget.statuses.map<DropdownMenuItem<AssistantEmployees>>((AssistantEmployees value) {
return DropdownMenuItem<AssistantEmployees>(
value: value,
child: Text(
value.user?.name ?? "NULL",
style: Theme.of(context).textTheme.titleMedium.copyWith(
color: Theme.of(context).primaryColor,
fontSize: 11,
//fontWeight: FontWeight.bold
),
),
);
}).toList(),
),
);
}
}

@ -10,8 +10,9 @@ import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class GasStatusMenu extends StatelessWidget {
final Function(Lookup) onSelect;
final Lookup initialValue;
final bool enabled;
const GasStatusMenu({Key key, this.onSelect, this.initialValue}) : super(key: key);
const GasStatusMenu({Key key, this.enabled = true, this.onSelect, this.initialValue}) : super(key: key);
@override
Widget build(BuildContext context) {
final settingProvider = Provider.of<SettingProvider>(context);
@ -29,6 +30,7 @@ class GasStatusMenu extends StatelessWidget {
initialStatus: initialValue,
statuses: menuProvider.items,
onSelect: onSelect,
enabled: enabled,
));
}
}

@ -26,7 +26,7 @@ class _SingleStatusMenuState extends State<FaultDescriptionMenu> {
void didUpdateWidget(covariant FaultDescriptionMenu oldWidget) {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element == widget.initialStatus;
return element.id == widget.initialStatus.id;
});
if (result.isNotEmpty) {
_selectedStatus = result.first;
@ -44,9 +44,11 @@ class _SingleStatusMenuState extends State<FaultDescriptionMenu> {
@override
void initState() {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element == widget.initialStatus;
return element.id == widget.initialStatus.id;
});
if (result.isNotEmpty) _selectedStatus = result.first;
if (widget.initialStatus.id != _selectedStatus?.id) {

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_users_provider.dart';
import 'package:test_sa/models/engineer.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/users_menu.dart';
class ServiceReportAllUsers extends StatelessWidget {
final Function(Engineer) onSelect;
final Engineer initialValue;
const ServiceReportAllUsers({Key key, @required this.onSelect, this.initialValue}) : super(key: key);
@override
Widget build(BuildContext context) {
ServiceReportUsersProvider menuProvider = Provider.of<ServiceReportUsersProvider>(context);
return LoadingManager(
isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.engineers == null,
stateCode: menuProvider.stateCode,
onRefresh: () async {
menuProvider.getAllUsers();
},
child: UsersMenu(
initialStatus: initialValue,
statuses: menuProvider.engineers,
onSelect: onSelect,
),
);
}
}

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/models/service_request/search_work_order.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/assistant_employee_menu.dart';
import '../../../../controllers/providers/api/status_drop_down/report/service_report_assistants_employee_provider.dart';
class ServiceReportAssistantEmployeeMenu extends StatelessWidget {
final Function(AssistantEmployees) onSelect;
final AssistantEmployees initialValue;
const ServiceReportAssistantEmployeeMenu({Key key, @required this.onSelect, this.initialValue}) : super(key: key);
@override
Widget build(BuildContext context) {
ServiceReportAssistantsEmployeeProvider menuProvider = Provider.of<ServiceReportAssistantsEmployeeProvider>(context);
return LoadingManager(
isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.assistantEmployees == null,
stateCode: menuProvider.stateCode,
onRefresh: () async {
await menuProvider.getAssistantEmployees();
},
child: AssistantEmployeeMenu(
initialStatus: initialValue,
statuses: menuProvider.assistantEmployees,
onSelect: onSelect,
),
);
}
}

@ -44,10 +44,10 @@ class _ServiceReportEquipmentStatusMenuState extends State<ServiceReportEquipmen
await callsLastSituationsProvider.getCalls(
user: userProvider.user,
host: settingProvider.host,
serviceStatus: widget.report.equipmentStatus?.id,
typeName: widget.report.type?.name,
id: widget.report.id,
woId: widget.request.id,
serviceStatus: widget.report?.equipmentStatus?.id,
typeName: widget.report?.type?.name,
id: widget.report?.id,
woId: widget.request?.id,
);
if (menuProvider.stateCode == null) {
menuProvider.reset();
@ -57,16 +57,16 @@ class _ServiceReportEquipmentStatusMenuState extends State<ServiceReportEquipmen
},
child: SingleStatusMenu(
statuses: menuProvider.statuses,
initialStatus: widget.report.equipmentStatus,
initialStatus: widget.report?.equipmentStatus,
onSelect: (status) {
widget.report.callLastSituation = null;
widget.report?.callLastSituation = null;
callsLastSituationsProvider.getCalls(
user: userProvider.user,
host: settingProvider.host,
serviceStatus: status.id,
id: widget.report.id,
woId: widget.request.id,
typeName: widget.report.type?.name,
serviceStatus: status?.id,
id: widget.report?.id,
woId: widget.request?.id,
typeName: widget.report?.type?.name,
);
widget.onSelect(status);

@ -14,6 +14,7 @@ class ServiceReportLastCallsMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
ServiceReportLastCallsProvider _menuProvider = Provider.of<ServiceReportLastCallsProvider>(context);
print("report?.callLastSituation:${report?.callLastSituation?.toMap()}");
return LoadingManager(
isLoading: _menuProvider.isLoading,
isFailedLoading: _menuProvider.calls == null,

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_maintenance_situation_provider.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class ServiceReportMaintenanceSituation extends StatelessWidget {
final Function(Lookup) onSelect;
final Lookup initialValue;
final String woId;
const ServiceReportMaintenanceSituation({
Key key,
@required this.onSelect,
@required this.initialValue,
@required this.woId,
}) : super(key: key);
@override
Widget build(BuildContext context) {
ServiceReportMaintenanceSituationProvider menuProvider = Provider.of<ServiceReportMaintenanceSituationProvider>(context);
return LoadingManager(
isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.operators == null,
stateCode: menuProvider.stateCode,
onRefresh: () async {
menuProvider.getOperators(woId);
},
child: SingleStatusMenu(
initialStatus: initialValue,
statuses: menuProvider.operators,
onSelect: onSelect,
),
);
}
}

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_visit_date_operator_provider.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
import 'package:test_sa/views/widgets/status/single_status_menu.dart';
class ServiceReportVisitDateOperator extends StatelessWidget {
final Function(Lookup) onSelect;
final Lookup initialValue;
const ServiceReportVisitDateOperator({Key key, @required this.onSelect, @required this.initialValue}) : super(key: key);
@override
Widget build(BuildContext context) {
ServiceReportVisitOperatorProvider menuProvider = Provider.of<ServiceReportVisitOperatorProvider>(context);
return LoadingManager(
isLoading: menuProvider.isLoading,
isFailedLoading: menuProvider.operators == null,
stateCode: menuProvider.stateCode,
onRefresh: () async {
menuProvider.getOperators();
},
child: SingleStatusMenu(
initialStatus: initialValue,
statuses: menuProvider.operators,
onSelect: onSelect,
),
);
}
}

@ -7,8 +7,9 @@ class SingleStatusMenu extends StatefulWidget {
final List<Lookup> statuses;
final Lookup initialStatus;
final Function(Lookup) onSelect;
final bool enabled;
const SingleStatusMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key);
const SingleStatusMenu({Key key, this.enabled = true, this.statuses, this.onSelect, this.initialStatus}) : super(key: key);
@override
_SingleStatusMenuState createState() => _SingleStatusMenuState();
@ -82,20 +83,22 @@ class _SingleStatusMenuState extends State<SingleStatusMenu> {
style: Theme.of(context).textTheme.subtitle1,
),
style: TextStyle(color: Theme.of(context).primaryColor),
underline: SizedBox.shrink(),
onChanged: (Lookup newValue) {
setState(() {
_selectedStatus = newValue;
});
widget.onSelect(newValue);
},
underline: const SizedBox.shrink(),
onChanged: widget.enabled == false
? null
: (Lookup newValue) {
setState(() {
_selectedStatus = newValue;
});
widget.onSelect(newValue);
},
items: widget.statuses.map<DropdownMenuItem<Lookup>>((Lookup value) {
return DropdownMenuItem<Lookup>(
value: value,
child: Text(
value.name,
style: Theme.of(context).textTheme.subtitle1.copyWith(
color: Theme.of(context).primaryColor,
color: widget.enabled ? Theme.of(context).primaryColor : Colors.grey,
fontSize: 11,
//fontWeight: FontWeight.bold
),

@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:test_sa/views/app_style/colors.dart';
import 'package:test_sa/views/app_style/sizing.dart';
import '../../../models/engineer.dart';
class UsersMenu extends StatefulWidget {
final List<Engineer> statuses;
final Engineer initialStatus;
final Function(Engineer) onSelect;
const UsersMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key);
@override
_SingleUsersMenuState createState() => _SingleUsersMenuState();
}
class _SingleUsersMenuState extends State<UsersMenu> {
Engineer _selectedStatus;
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(fn);
}
@override
void didUpdateWidget(covariant UsersMenu oldWidget) {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element == widget.initialStatus;
});
if (result.isNotEmpty) {
_selectedStatus = result.first;
} else {
_selectedStatus = null;
}
if ((widget.initialStatus?.id ?? "") != (_selectedStatus?.id ?? "")) {
widget.onSelect(_selectedStatus);
}
} else {
_selectedStatus = null;
}
super.didUpdateWidget(oldWidget);
}
@override
void initState() {
if (widget.initialStatus != null) {
final result = widget.statuses?.where((element) {
return element == widget.initialStatus;
});
if (result.isNotEmpty) _selectedStatus = result.first;
if (widget.initialStatus.id != _selectedStatus?.id) {
widget.onSelect(_selectedStatus);
}
}
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AColors.inputFieldBackgroundColor,
border: Border.all(
color: Color(0xffefefef),
),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
// boxShadow: const [
// AppStyle.boxShadow
// ]
),
child: DropdownButton<Engineer>(
value: _selectedStatus,
iconSize: 24,
icon: const Icon(Icons.keyboard_arrow_down_rounded),
elevation: 0,
isExpanded: true,
hint: Text(
"Select",
style: Theme.of(context).textTheme.subtitle1,
),
style: TextStyle(color: Theme.of(context).primaryColor),
underline: SizedBox.shrink(),
onChanged: (Engineer newValue) {
setState(() {
_selectedStatus = newValue;
});
widget.onSelect(newValue);
},
items: widget.statuses.map<DropdownMenuItem<Engineer>>((Engineer value) {
return DropdownMenuItem<Engineer>(
value: value,
child: Text(
value.name,
style: Theme.of(context).textTheme.subtitle1.copyWith(
color: Theme.of(context).primaryColor,
fontSize: 11,
//fontWeight: FontWeight.bold
),
),
);
}).toList(),
),
);
}
}

@ -9,11 +9,13 @@ class AppTimer extends StatefulWidget {
final TimerModel timer;
final Future<bool> Function(TimerModel) onChange;
final TextStyle style;
final bool enabled;
const AppTimer({
Key key,
this.timer,
this.onChange,
this.style,
this.enabled = true,
}) : super(key: key);
@override
@ -32,7 +34,7 @@ class _AppTimerState extends State<AppTimer> {
_startTimer() async {
if (!_running) {
final time = DateTime.now();
bool result = await widget.onChange(TimerModel(startAt: time, endAt: null, durationInSecond: _delay));
bool result = await widget.onChange(TimerModel(startAt: time, endAt: null, durationInSecond: _delay, stopped: false));
if (!result) return;
_running = true;
@ -52,7 +54,7 @@ class _AppTimerState extends State<AppTimer> {
_stopTimer() async {
final time = DateTime.now();
final tempStartAt = _startAt.add(Duration(seconds: _delay));
bool result = await widget.onChange(TimerModel(startAt: tempStartAt, endAt: time, durationInSecond: _delay));
bool result = await widget.onChange(TimerModel(startAt: tempStartAt, endAt: time, durationInSecond: _delay, stopped: true));
if (!result) return;
_running = false;
_endAt = time;
@ -99,7 +101,7 @@ class _AppTimerState extends State<AppTimer> {
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: const Size(1, 1), padding: EdgeInsets.all(4 * AppStyle.getScaleFactor(context)), backgroundColor: _running ? AColors.green[300] : AColors.grey, foregroundColor: Colors.black),
onPressed: _loading ? null : _onPressed,
onPressed: _loading || widget.enabled == false ? null : _onPressed,
child: _loading
? const SizedBox.square(
dimension: 18,
@ -108,7 +110,7 @@ class _AppTimerState extends State<AppTimer> {
))
: Row(
children: [
Icon(_running ? Icons.pause : Icons.play_arrow),
if (widget.enabled) Icon(_running ? Icons.pause : Icons.play_arrow),
Expanded(
child: Center(
child: ValueListenableBuilder<String>(
@ -116,7 +118,7 @@ class _AppTimerState extends State<AppTimer> {
builder: (context, value, _) {
return Text(
value,
style: widget.style,
style: widget.enabled ? widget.style : widget.style?.copyWith(color: Colors.black54),
);
}),
),

@ -60,6 +60,7 @@ dependencies:
audioplayers: ^1.1.1
flare_flutter: ^3.0.2
signature: ^5.3.0
flutter_svg: ^1.1.6
dev_dependencies:

Loading…
Cancel
Save