internal audit api's implementation in progress
parent
81dd799672
commit
81dd189025
@ -0,0 +1,56 @@
|
||||
import 'package:test_sa/models/timer_model.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
|
||||
|
||||
class AuditFormModel {
|
||||
int? id;
|
||||
String? createdDate;
|
||||
int? requestId;
|
||||
String? debrief;
|
||||
DateTime? startTime;
|
||||
DateTime? endTime;
|
||||
double? totalHours;
|
||||
List<InternalAuditAttachments>? attachments;
|
||||
bool? isComplete;
|
||||
TimerModel? auditTimerModel = TimerModel();
|
||||
|
||||
AuditFormModel({
|
||||
this.id,
|
||||
this.requestId,
|
||||
this.debrief,
|
||||
this.startTime,
|
||||
this.endTime,
|
||||
this.totalHours,
|
||||
this.createdDate,
|
||||
this.attachments,
|
||||
this.isComplete,
|
||||
this.auditTimerModel,
|
||||
});
|
||||
|
||||
AuditFormModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
requestId = json['requestId'];
|
||||
debrief = json['debrief'];
|
||||
startTime = json['startTime'] != null ? DateTime.tryParse(json['startTime']) : null;
|
||||
endTime = json['endTime'] != null ? DateTime.tryParse(json['endTime']) : null;
|
||||
totalHours = json['totalHours']?.toDouble();
|
||||
if (json['attachments'] != null) {
|
||||
attachments = (json['attachments'] as List)
|
||||
.map((e) => InternalAuditAttachments.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
isComplete = json['isComplete'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'requestId': requestId,
|
||||
'debrief': debrief,
|
||||
'startTime': startTime?.toIso8601String(),
|
||||
'endTime': endTime?.toIso8601String(),
|
||||
'totalHours': totalHours,
|
||||
'attachments': attachments?.map((e) => e.toJson()).toList(),
|
||||
'isComplete': isComplete,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
class InternalAuditTimerModel {
|
||||
int? id;
|
||||
String? startDate;
|
||||
String? endDate;
|
||||
double? totalWorkingHour;
|
||||
String? comment;
|
||||
|
||||
InternalAuditTimerModel({
|
||||
this.id,
|
||||
this.startDate,
|
||||
this.endDate,
|
||||
this.totalWorkingHour,
|
||||
this.comment,
|
||||
});
|
||||
|
||||
factory InternalAuditTimerModel.fromJson(Map<String, dynamic> json) {
|
||||
return InternalAuditTimerModel(
|
||||
id: json['id'] as int?,
|
||||
startDate: json['startDate'],
|
||||
endDate: json['endDate'],
|
||||
totalWorkingHour: (json['totalWorkingHours'] as num?)?.toDouble(),
|
||||
comment: json['comment'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'startDate': startDate,
|
||||
'endDate': endDate,
|
||||
'totalWorkingHours': totalWorkingHour,
|
||||
'comment': comment,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
import 'package:test_sa/models/lookup.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/models/system_internal_audit_form_model.dart';
|
||||
|
||||
class SystemInternalAuditDataModel {
|
||||
int? id;
|
||||
int? assetGroupId;
|
||||
String? requestNo;
|
||||
int? requestNoSequence;
|
||||
Auditor? auditor;
|
||||
Lookup? status;
|
||||
Lookup? findingType;
|
||||
String? findingDescription;
|
||||
Lookup? workOrderType;
|
||||
Auditor? assignEmployee;
|
||||
SystemAuditWorkOrderDetailModel? workOrderDetails; // Already exists as a separate model
|
||||
String? createdBy;
|
||||
String? createdDate;
|
||||
String? modifiedBy;
|
||||
String? modifiedDate;
|
||||
|
||||
SystemInternalAuditDataModel({
|
||||
this.id,
|
||||
this.assetGroupId,
|
||||
this.requestNo,
|
||||
this.requestNoSequence,
|
||||
this.auditor,
|
||||
this.status,
|
||||
this.findingType,
|
||||
this.findingDescription,
|
||||
this.workOrderType,
|
||||
this.assignEmployee,
|
||||
this.workOrderDetails,
|
||||
this.createdBy,
|
||||
this.createdDate,
|
||||
this.modifiedBy,
|
||||
this.modifiedDate,
|
||||
});
|
||||
|
||||
SystemInternalAuditDataModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
assetGroupId = json['assetGroupId'];
|
||||
requestNo = json['requestNo'];
|
||||
requestNoSequence = json['requestNoSequence'];
|
||||
auditor = json['auditor'] != null ? Auditor.fromJson(json['auditor']) : null;
|
||||
status = json['status'] != null ? Lookup.fromJson(json['status']) : null;
|
||||
findingType = json['findingType'] != null ? Lookup.fromJson(json['findingType']) : null;
|
||||
findingDescription = json['findingDescription'];
|
||||
workOrderType = json['workOrderType'] != null ? Lookup.fromJson(json['workOrderType']) : null;
|
||||
assignEmployee = json['assignEmployee'] != null ? Auditor.fromJson(json['assignEmployee']) : null;
|
||||
workOrderDetails = json['workOrderDetails'] != null ? SystemAuditWorkOrderDetailModel.fromJson(json['workOrderDetails']) : null; // Keep as-is
|
||||
createdBy = json['createdBy'];
|
||||
createdDate = json['createdDate'];
|
||||
modifiedBy = json['modifiedBy'];
|
||||
modifiedDate = json['modifiedDate'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = {};
|
||||
data['id'] = id;
|
||||
data['assetGroupId'] = assetGroupId;
|
||||
data['requestNo'] = requestNo;
|
||||
data['requestNoSequence'] = requestNoSequence;
|
||||
if (auditor != null) data['auditor'] = auditor!.toJson();
|
||||
if (status != null) data['status'] = status!.toJson();
|
||||
if (findingType != null) data['findingType'] = findingType!.toJson();
|
||||
data['findingDescription'] = findingDescription;
|
||||
if (workOrderType != null) data['workOrderType'] = workOrderType!.toJson();
|
||||
if (assignEmployee != null) data['assignEmployee'] = assignEmployee!.toJson();
|
||||
data['workOrderDetails'] = workOrderDetails;
|
||||
data['createdBy'] = createdBy;
|
||||
data['createdDate'] = createdDate;
|
||||
data['modifiedBy'] = modifiedBy;
|
||||
data['modifiedDate'] = modifiedDate;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Auditor {
|
||||
String? userId;
|
||||
String? userName;
|
||||
String? email;
|
||||
String? employeeId;
|
||||
int? languageId;
|
||||
String? extensionNo;
|
||||
String? phoneNumber;
|
||||
bool? isActive;
|
||||
|
||||
Auditor({
|
||||
this.userId,
|
||||
this.userName,
|
||||
this.email,
|
||||
this.employeeId,
|
||||
this.languageId,
|
||||
this.extensionNo,
|
||||
this.phoneNumber,
|
||||
this.isActive,
|
||||
});
|
||||
|
||||
Auditor.fromJson(Map<String, dynamic> json) {
|
||||
userId = json['userId'];
|
||||
userName = json['userName'];
|
||||
email = json['email'];
|
||||
employeeId = json['employeeId'];
|
||||
languageId = json['languageId'];
|
||||
extensionNo = json['extensionNo'];
|
||||
phoneNumber = json['phoneNumber'];
|
||||
isActive = json['isActive'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = {};
|
||||
data['userId'] = userId;
|
||||
data['userName'] = userName;
|
||||
data['email'] = email;
|
||||
data['employeeId'] = employeeId;
|
||||
data['languageId'] = languageId;
|
||||
data['extensionNo'] = extensionNo;
|
||||
data['phoneNumber'] = phoneNumber;
|
||||
data['isActive'] = isActive;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,342 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:test_sa/controllers/api_routes/api_manager.dart';
|
||||
import 'package:test_sa/controllers/providers/api/user_provider.dart';
|
||||
import 'package:test_sa/extensions/context_extension.dart';
|
||||
import 'package:test_sa/extensions/int_extensions.dart';
|
||||
import 'package:test_sa/extensions/string_extensions.dart';
|
||||
import 'package:test_sa/extensions/text_extensions.dart';
|
||||
import 'package:test_sa/extensions/widget_extensions.dart';
|
||||
import 'package:test_sa/models/generic_attachment_model.dart';
|
||||
import 'package:test_sa/models/timer_model.dart';
|
||||
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
|
||||
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/models/audit_form_model.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/models/equipment_internal_audit_data_model.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/models/internal_audit_attachment_model.dart';
|
||||
import 'package:test_sa/modules/internal_audit_module/provider/internal_audit_provider.dart';
|
||||
import 'package:test_sa/new_views/app_style/app_color.dart';
|
||||
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
|
||||
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
|
||||
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
||||
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
|
||||
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
|
||||
import 'package:test_sa/views/widgets/loaders/loading_manager.dart';
|
||||
import 'package:test_sa/views/widgets/timer/app_timer.dart';
|
||||
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
|
||||
|
||||
class UpdateEquipmentInternalAuditPage extends StatefulWidget {
|
||||
static const String id = "update-equipment-internal-audit";
|
||||
EquipmentInternalAuditDataModel? model;
|
||||
|
||||
UpdateEquipmentInternalAuditPage({Key? key,this.model}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<UpdateEquipmentInternalAuditPage> createState() => _UpdateEquipmentInternalAuditPageState();
|
||||
}
|
||||
|
||||
class _UpdateEquipmentInternalAuditPageState extends State<UpdateEquipmentInternalAuditPage> {
|
||||
final bool _isLoading = false;
|
||||
double totalWorkingHours = 0.0;
|
||||
AuditFormModel formModel = AuditFormModel();
|
||||
final TextEditingController _workingHoursController = TextEditingController();
|
||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
List<GenericAttachmentModel> _attachments = [];
|
||||
//TODO need to check if it's needed or not..
|
||||
List<TimerHistoryModel> timerList = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
populateForm();
|
||||
super.initState();
|
||||
}
|
||||
void populateForm(){
|
||||
formModel.requestId = widget.model?.id;
|
||||
formModel.id = widget.model?.id;
|
||||
_attachments = widget.model?.attachments?.map((e) => GenericAttachmentModel(id: e.id?.toInt()??0, name: e.name!)).toList() ?? [];
|
||||
|
||||
}
|
||||
void calculateWorkingTime() {
|
||||
// final timers = _formModel.gasRefillTimers ?? [];
|
||||
// totalWorkingHours = timers.fold<double>(0.0, (sum, item) {
|
||||
// if (item.startDate == null || item.endDate == null) return sum;
|
||||
// try {
|
||||
// final start = DateTime.parse(item.startDate!);
|
||||
// final end = DateTime.parse(item.endDate!);
|
||||
// final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
|
||||
// return sum + diffInHours;
|
||||
// } catch (_) {
|
||||
// return sum;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// timerList = timers.map((e) {
|
||||
// return TimerHistoryModel(
|
||||
// id: e.id,
|
||||
// startTime: e.startDate,
|
||||
// endTime: e.endDate,
|
||||
// workingHours: e.workingHours,
|
||||
// );
|
||||
// }).toList();
|
||||
}
|
||||
|
||||
|
||||
_onSubmit(BuildContext context) async {
|
||||
bool isTimerPickerEnable = ApiManager.instance.assetGroup?.enabledEngineerTimer ?? false;
|
||||
InternalAuditProvider provider = Provider.of<InternalAuditProvider>(context,listen: false);
|
||||
|
||||
_formKey.currentState!.save();
|
||||
formModel.attachments = [];
|
||||
for (var item in _attachments) {
|
||||
String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '')
|
||||
? ("${item.name?.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}")
|
||||
: item.name ?? '';
|
||||
formModel.attachments!.add(
|
||||
InternalAuditAttachments(
|
||||
id: item.id,
|
||||
originalName: fileName,
|
||||
// name: fileName,
|
||||
),
|
||||
);
|
||||
}
|
||||
provider.updateEquipmentInternalAudit(model: formModel);
|
||||
|
||||
log('payload ${formModel.toJson()}');
|
||||
|
||||
|
||||
|
||||
// if (isTimerPickerEnable) {
|
||||
// if (_formModel.timer?.startAt == null && _formModel.gasRefillTimePicker == null) {
|
||||
// Fluttertoast.showToast(msg: "Working Hours Required");
|
||||
// return false;
|
||||
// }
|
||||
// if (_formModel.gasRefillTimePicker == null) {
|
||||
// if (_formModel.timer?.startAt == null) {
|
||||
// Fluttertoast.showToast(msg: "Working Hours Required");
|
||||
// return false;
|
||||
// }
|
||||
// if (_formModel.timer?.endAt == null) {
|
||||
// Fluttertoast.showToast(msg: "Please Stop The Timer");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// if (_formModel.timer?.startAt == null) {
|
||||
// Fluttertoast.showToast(msg: "Working Hours Required");
|
||||
// return false;
|
||||
// }
|
||||
// if (_formModel.timer?.endAt == null) {
|
||||
// Fluttertoast.showToast(msg: "Please Stop The Timer");
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (_currentDetails.deliverdQty == null) {
|
||||
// await Fluttertoast.showToast(msg: "Delivered Quantity is Required");
|
||||
// return false;
|
||||
// }
|
||||
// _formModel.gasRefillDetails = [];
|
||||
// _formModel.gasRefillDetails?.add(_currentDetails);
|
||||
//
|
||||
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
|
||||
// _formModel.gasRefillTimers = _formModel.gasRefillTimers ?? [];
|
||||
// if (_formModel.gasRefillTimePicker != null) {
|
||||
// int durationInSecond = _formModel.gasRefillTimePicker!.endAt!.difference(_formModel.gasRefillTimePicker!.startAt!).inSeconds;
|
||||
// _formModel.gasRefillTimers?.add(
|
||||
// GasRefillTimer(
|
||||
// id: 0,
|
||||
// startDate: _formModel.gasRefillTimePicker!.startAt!.toIso8601String(), // Handle potential null
|
||||
// endDate: _formModel.gasRefillTimePicker!.endAt?.toIso8601String(), // Handle potential null
|
||||
// workingHours: ((durationInSecond) / 60 / 60),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// _formModel.timerModelList?.forEach((timer) {
|
||||
// int durationInSecond = timer.endAt!.difference(timer.startAt!).inSeconds;
|
||||
// _formModel.gasRefillTimers?.add(
|
||||
// GasRefillTimer(
|
||||
// id: 0,
|
||||
// startDate: timer.startAt!.toIso8601String(), // Handle potential null
|
||||
// endDate: timer.endAt?.toIso8601String(), // Handle potential null
|
||||
// workingHours: ((durationInSecond) / 60 / 60),
|
||||
// ),
|
||||
// );
|
||||
// });
|
||||
// _formModel.gasRefillAttachments = [];
|
||||
// for (var item in _attachments) {
|
||||
// String fileName = ServiceRequestUtils.isLocalUrl(item.name??'') ? ("${item.name??''.split("/").last}|${base64Encode(File(item.name??'').readAsBytesSync())}") :item.name??'';
|
||||
// _formModel.gasRefillAttachments?.add(GasRefillAttachments(
|
||||
// id: item.id, gasRefillId: _formModel.id ?? 0, attachmentName: fileName));
|
||||
// }
|
||||
|
||||
// await _gasRefillProvider?.updateGasRefill(status: status, model: _formModel).then((success) {
|
||||
// Navigator.pop(context);
|
||||
// if (success) {
|
||||
// if (status == 1) {
|
||||
// AllRequestsProvider allRequestsProvider = Provider.of<AllRequestsProvider>(context, listen: false);
|
||||
// // when click complete then this request remove from the list and status changes to closed..
|
||||
// _gasRefillProvider?.reset();
|
||||
// allRequestsProvider.getAllRequests(context, typeTransaction: 2);
|
||||
// }
|
||||
// Navigator.pop(context);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_workingHoursController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void updateTimer({TimerModel? timer}) {
|
||||
if (timer?.startAt != null && timer?.endAt != null) {
|
||||
final start = timer!.startAt!;
|
||||
final end = timer.endAt!;
|
||||
|
||||
final difference = end.difference(start);
|
||||
final totalHours = difference.inSeconds / 3600.0;
|
||||
formModel.startTime = start;
|
||||
formModel.endTime = end;
|
||||
formModel.totalHours = totalHours;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: DefaultAppBar(
|
||||
title: 'Update Information'.addTranslation,
|
||||
onWillPopScope: () {
|
||||
formModel.isComplete = false;
|
||||
_onSubmit(context);
|
||||
},
|
||||
),
|
||||
key: _scaffoldKey,
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: LoadingManager(
|
||||
isLoading: _isLoading,
|
||||
isFailedLoading: false,
|
||||
stateCode: 200,
|
||||
onRefresh: () async {},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
8.height,
|
||||
AppTextFormField(
|
||||
labelText: 'Debrief'.addTranslation,
|
||||
textInputType: TextInputType.multiline,
|
||||
hintStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
|
||||
labelStyle: TextStyle(color: context.isDark ? AppColor.white10 : AppColor.black10),
|
||||
alignLabelWithHint: true,
|
||||
initialValue: formModel.debrief,
|
||||
backgroundColor: AppColor.fieldBgColor(context),
|
||||
showShadow: false,
|
||||
onSaved: (value) {
|
||||
formModel.debrief = value;
|
||||
},
|
||||
),
|
||||
8.height,
|
||||
_timerWidget(context, totalWorkingHours),
|
||||
16.height,
|
||||
AttachmentPicker(
|
||||
label: context.translation.attachFiles,
|
||||
attachment: _attachments,
|
||||
buttonColor: AppColor.primary10,
|
||||
onlyImages: false,
|
||||
buttonIcon: 'image-plus'.toSvgAsset(
|
||||
color: AppColor.primary10,
|
||||
),
|
||||
),
|
||||
8.height,
|
||||
],
|
||||
).toShadowContainer(context),
|
||||
).expanded,
|
||||
FooterActionButton.footerContainer(
|
||||
context: context,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
AppFilledButton(
|
||||
label: context.translation.save,
|
||||
buttonColor: context.isDark ? AppColor.neutral70 : AppColor.white60,
|
||||
textColor: context.isDark ? AppColor.white10 : AppColor.black10,
|
||||
onPressed: (){
|
||||
formModel.isComplete = false;
|
||||
_onSubmit(context);
|
||||
}
|
||||
).expanded,
|
||||
12.width,
|
||||
AppFilledButton(
|
||||
label: context.translation.complete,
|
||||
buttonColor: AppColor.primary10,
|
||||
onPressed: (){
|
||||
formModel.isComplete = true;
|
||||
_onSubmit(context);
|
||||
}
|
||||
).expanded,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
).handlePopScope(
|
||||
cxt: context,
|
||||
onSave: () {
|
||||
formModel.isComplete=false;
|
||||
_onSubmit(context);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _timerWidget(BuildContext context, double totalWorkingHours) {
|
||||
TimerModel? timer = TimerModel();
|
||||
TimerModel? timerPicker;
|
||||
List<TimerModel>? timerModelList = [];
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
AppTimer(
|
||||
label: context.translation.workingHours,
|
||||
timer: timer,
|
||||
pickerFromDate: DateTime.tryParse(widget.model?.createdDate ?? ''),
|
||||
pickerTimer: timerPicker,
|
||||
onPick: (time) {
|
||||
updateTimer(timer: timer);
|
||||
|
||||
},
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.fieldBgColor(context),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
timerProgress: (isRunning) {},
|
||||
onChange: (timer) async {
|
||||
updateTimer(timer: timer);
|
||||
log('here onChange ${timer.startAt}');
|
||||
|
||||
return true;
|
||||
},
|
||||
),
|
||||
if (totalWorkingHours > 0.0) ...[
|
||||
12.height,
|
||||
WorkingTimeTile(
|
||||
timerList: timerList,
|
||||
totalWorkingTime: totalWorkingHours,
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue