diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 2c8c2a6b..0930ace5 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -4,14 +4,14 @@ class URLs { static const String appReleaseBuildNumber = "31"; // static const host1 = "https://atomsm.hmg.com"; // production url - static const host1 = "https://atomsmdev.hmg.com"; // local DEV url - // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url + // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url + static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url // static String _baseUrl = "$_host/mobile"; - // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module + static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + // static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/mobile"; // host local UAT and for internal audit dev // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart index d0e5d156..9ae0e6ce 100644 --- a/lib/dashboard_latest/widgets/request_category_list.dart +++ b/lib/dashboard_latest/widgets/request_category_list.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_item_view.dart'; import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart'; import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart'; import 'package:test_sa/modules/tm_module/tasks/task_request_item_view.dart'; @@ -62,6 +63,8 @@ class RequestCategoryList extends StatelessWidget { return EquipmentInternalAuditItemView(requestData: request); case 11: return EquipmentInternalAuditItemView(requestData: request); + case 13: + return AssetDeliveryItemView(requestData: request); default: return Container( height: 100, diff --git a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart index 08de3111..cde76346 100644 --- a/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart +++ b/lib/modules/asset_delivery_module/models/asset_delivery_data_model.dart @@ -241,7 +241,7 @@ class AssetDeliveryInternalDetail { num? qtyCancelled; num? unitPrice; num? unitPriceWithTax; - String? itemCategory; + Lookup? itemCategory; num? totalAssets; num? childPerAsset; @@ -259,7 +259,9 @@ class AssetDeliveryInternalDetail { qtyCancelled = json['qtyCancelled']; unitPrice = json['unitPrice']; unitPriceWithTax = json['unitPriceWithTax']; - itemCategory = json['itemCategory']; + itemCategory = json['itemCategory'] != null + ? Lookup.fromJson(json['itemCategory']) + : null; totalAssets = json['totalAssets']; childPerAsset = json['childPerAsset']; } diff --git a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart index 64671b11..fafcc277 100644 --- a/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart +++ b/lib/modules/asset_delivery_module/models/technical_inspection_asset_model.dart @@ -136,7 +136,7 @@ class TechnicalInspectionAssetModel { Map toChildJson() { final Map data = {}; - data['id'] = id; + data['id'] = id ?? 0; data['assetDeliveryInternalDetailAssetChildId'] = assetDeliveryInternalDetailAssetChildId; data['assetNumber'] = assetNumber; data['assetOriginId'] = assetOrigin?.id; diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart index c6918f74..cdb4d5e9 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/delivery_inspection_form_view.dart @@ -7,7 +7,6 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/modules/asset_delivery_module/helper_function.dart'; import 'package:test_sa/modules/asset_delivery_module/models/asset_delivery_data_model.dart'; @@ -15,7 +14,6 @@ import 'package:test_sa/modules/asset_delivery_module/models/delivery_inspection import 'package:test_sa/modules/asset_delivery_module/models/delivery_line_model.dart'; import 'package:test_sa/modules/asset_delivery_module/models/inspection_person_model.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/asset_delivery_line_card_view.dart'; -import 'package:test_sa/modules/asset_delivery_module/pages/attachment_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/cost_center_form_view.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart'; import 'package:test_sa/modules/asset_delivery_module/pages/end_user_acceptance/end_user_cost_center_list_view.dart'; @@ -205,13 +203,22 @@ class _DeliveryInspectionFormViewState extends State } void calculateTotalTime() { - if (model.deliveryInspectionInspectedDateFrom == null || model.deliveryInspectionInspectedDateTo == null) { + final from = model.deliveryInspectionInspectedDateFrom; + final to = model.deliveryInspectionInspectedDateTo; + + if (from == null || to == null) { model.totalTime = null; return; } - final fromDate = model.deliveryInspectionInspectedDateFrom!; - final toDate = model.deliveryInspectionInspectedDateTo!; - final hours = toDate.difference(fromDate).inSeconds / 3600.0; + + final diffInSeconds = to.difference(from).inSeconds; + + if (diffInSeconds < 0) { + model.totalTime = null; + return; + } + + final hours = diffInSeconds / 3600; model.totalTime = num.parse(hours.toStringAsFixed(3)); } @@ -253,6 +260,7 @@ class _DeliveryInspectionFormViewState extends State }, ), if (widget.requestModel?.paymentTerm?.value == 2) ...[ + 8.height, _inspectionTile( title: 'Third Approved by'.addTranslation, model: model.thirdApprovalModel, @@ -330,52 +338,31 @@ class _DeliveryInspectionFormViewState extends State date: model.deliveryInspectionInspectedDateFrom, from: DateTime(DateTime.now().year, 1, 1), formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( + onDatePicker: (selectedDate) async { + final selectedTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - model.deliveryInspectionInspectedDateFrom = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - // calculateTotalTime(); - - ///need to check if need validation or not. - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - if (model.deliveryInspectionInspectedDateFrom!.isAfter(DateTime.now())) { - "Start time is after than current time".showToast; - model.deliveryInspectionInspectedDateFrom = null; - selectedTime = null; - return; - } - - setState(() {}); - } - }); + builder: _timePickerThemeBuilder, + ); + if (selectedTime == null) return; + + final fromDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!_validateInspectionDates(from: fromDateTime, to: model.deliveryInspectionInspectedDateTo)) { + return; // invalid, do not assign + } + + model.deliveryInspectionInspectedDateFrom = fromDateTime; + setState(() {}); }, ), + 8.height, ADatePicker( label: 'Inspected Date/Time To'.addTranslation, @@ -385,55 +372,109 @@ class _DeliveryInspectionFormViewState extends State date: model.deliveryInspectionInspectedDateTo, from: model.deliveryInspectionInspectedDateFrom, formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( + onDatePicker: (selectedDate) async { + if (model.deliveryInspectionInspectedDateFrom == null) { + "Please select time to first".showToast; + return; + } + + final selectedTime = await showTimePicker( context: context, initialTime: TimeOfDay.now(), - builder: (BuildContext context, Widget? child) { - final ThemeData currentTheme = Theme.of(context); - return Theme( - data: currentTheme.copyWith( - timePickerTheme: TimePickerThemeData( - dialHandColor: AppColor.primary10, - dialBackgroundColor: Colors.grey.withOpacity(0.1), - hourMinuteColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1)), - dayPeriodColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent), - dayPeriodTextColor: MaterialStateColor.resolveWith((states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10), - dayPeriodBorderSide: BorderSide(color: Colors.grey.withOpacity(0.2)), - entryModeIconColor: AppColor.primary10, - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: AppColor.primary10)), - ), - child: child!, - ); - }, - ).then((selectedTime) { - if (selectedTime != null) { - model.deliveryInspectionInspectedDateTo = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - calculateTotalTime(); - - ///Need to check need validation or not.. - // if (widget.pickerFromDate != null && _pickerStartAt!.isBefore(widget.pickerFromDate!)) { - // "Start time is before the request time.".showToast; - // _pickerStartAt = null; - // selectedTime = null; - // return; - // } - if (model.deliveryInspectionInspectedDateTo!.isAfter(DateTime.now())) { - "End time is after than current time".showToast; - model.deliveryInspectionInspectedDateTo = null; - selectedTime = null; - return; - } - setState(() {}); - } - }); + builder: _timePickerThemeBuilder, + ); + if (selectedTime == null) return; + + final toDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + + if (!_validateInspectionDates(from: model.deliveryInspectionInspectedDateFrom, to: toDateTime)) { + return; // invalid, do not assign + } + + model.deliveryInspectionInspectedDateTo = toDateTime; + setState(() {}); }, ), ], ); } + bool _validateInspectionDates({DateTime? from, DateTime? to}) { + if (from == null && to == null) return true; + if (from != null) { + if (from.isAfter(DateTime.now())) { + "Start time cannot be in the future".showToast; + return false; + } + if (to != null && from.isAfter(to)) { + "Start time cannot be after end time".showToast; + return false; + } + } + if (to != null) { + if (to.isAfter(DateTime.now())) { + "End time cannot be in the future".showToast; + return false; + } + if (from != null && to.isBefore(from)) { + "End time cannot be before start time".showToast; + return false; + } + } + + if (from != null && to != null) { + final diffInSeconds = to.difference(from).inSeconds; + if (diffInSeconds < 0) { + model.totalTime = null; + return false; + } + final hours = diffInSeconds / 3600.0; + model.totalTime = num.parse(hours.toStringAsFixed(3)); + } else { + model.totalTime = null; + } + + return true; + } + + Widget _timePickerThemeBuilder(BuildContext context, Widget? child) { + final ThemeData currentTheme = Theme.of(context); + + return Theme( + data: currentTheme.copyWith( + timePickerTheme: TimePickerThemeData( + dialHandColor: AppColor.primary10, + dialBackgroundColor: Colors.grey.withOpacity(0.1), + hourMinuteColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.grey.withOpacity(0.1), + ), + dayPeriodColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? AppColor.primary10 : Colors.transparent, + ), + dayPeriodTextColor: MaterialStateColor.resolveWith( + (states) => states.contains(MaterialState.selected) ? Colors.white : AppColor.primary10, + ), + dayPeriodBorderSide: BorderSide( + color: Colors.grey.withOpacity(0.2), + ), + entryModeIconColor: AppColor.primary10, + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: AppColor.primary10, + ), + ), + ), + child: child!, + ); + } + Widget inspectionDetails() { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart index bd81f92a..106b3a97 100644 --- a/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart +++ b/lib/modules/asset_delivery_module/pages/delivery_inspection/inpection_bottomsheet.dart @@ -15,10 +15,10 @@ import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; class InspectionPersonBottomSheet extends StatefulWidget { final String title; - bool isHmg; + bool isHmg; final InspectionPersonModel model; - InspectionPersonBottomSheet({ + InspectionPersonBottomSheet({ super.key, required this.title, required this.isHmg, @@ -42,8 +42,6 @@ class _InspectionPersonBottomSheetState extends State createState() => _UpdateEndUserAssetDetailsViewState(); +// } +// +// class _UpdateEndUserAssetDetailsViewState extends State { +// final GlobalKey _formKey = GlobalKey(); +// final GlobalKey _scaffoldKey = GlobalKey(); +// bool viewOnly = false; +// late AssetDeliveryProvider assetDeliveryProvider; +// EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); +// late TextEditingController quantityController; +// late TextEditingController descriptionController; +// +// @override +// void initState() { +// quantityController = TextEditingController(); +// descriptionController = TextEditingController(); +// WidgetsBinding.instance.addPostFrameCallback((_) { +// getInitialData(); +// }); +// super.initState(); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// void getInitialData() async { +// assetDeliveryProvider = Provider.of(context, listen: false); +// if (widget.assetDetailsModel != null) { +// model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); +// model.costCenterName = widget.costCenterName; +// model.assetDeliveryExternalDeliveryId = widget.tableId; +// model.status = widget.assetDetailsModel?.status; +// model.rejectionReason = widget.assetDetailsModel?.rejectionReason; +// } +// quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; +// descriptionController.text = model.description ?? ''; +// model.type = 'Accessory'; +// setState(() {}); +// } +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// key: _scaffoldKey, +// appBar: DefaultAppBar( +// title: 'Item Details'.addTranslation, +// titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), +// ), +// body: Form( +// key: _formKey, +// child: Column( +// children: [ +// SingleChildScrollView( +// padding: const EdgeInsets.all(16), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Status'.addTranslation, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// validator: (value) { +// if (value == null) return "Please select status"; +// return null; +// }, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.status, +// onSelect: (status) { +// if (status != null) { +// model.status = status; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// if (model.type == 'Accessory') ...[ +// AppTextFormField( +// labelText: 'Rejected Quantity'.addTranslation, +// controller: quantityController, +// backgroundColor: AppColor.fieldBgColor(context), +// textAlign: TextAlign.center, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// textInputType: TextInputType.number, +// showShadow: false, +// validator: (value) { +// if ((value ?? "").isEmpty) return "Mandatory"; +// return null; +// }, +// onChange: (value) { +// if (value.isNotEmpty) { +// model.rejectedQty = model.rejectedQty = num.tryParse(value); +// setState(() {}); +// } +// }, +// style: Theme.of(context).textTheme.titleMedium, +// ), +// 8.height, +// if (model.status?.value == 1 && (model.rejectedQty != null && quantityController.text.isNotEmpty && model.rejectedQty! > 0)) +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Rejection Reason '.addTranslation, +// validator: (value) { +// if (value == null) return "Please select rejection reason"; +// return null; +// }, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.rejectionReason, +// onSelect: (reason) { +// if (reason != null) { +// model.rejectionReason = reason; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// ], +// if (model.status != null && model.status!.value == 2) ...[ +// SingleItemDropDownMenu( +// context: context, +// height: 56.toScreenHeight, +// title: 'Rejection Reason '.addTranslation, +// validator: (value) { +// if (value == null) return "Please select rejection reason"; +// return null; +// }, +// titleTextColor: AppColor.neutral120, +// showShadow: false, +// backgroundColor: AppColor.fieldBgColor(context), +// showAsBottomSheet: true, +// initialValue: model.rejectionReason, +// onSelect: (reason) { +// if (reason != null) { +// model.rejectionReason = reason; +// setState(() {}); +// } +// }, +// ), +// 8.height, +// ], +// AppTextFormField( +// controller: descriptionController, +// labelText: 'Description'.addTranslation, +// backgroundColor: AppColor.fieldBgColor(context), +// showShadow: false, +// labelStyle: AppTextStyles.textFieldLabelStyle, +// alignLabelWithHint: true, +// textInputType: TextInputType.multiline, +// onChange: (value) { +// model.description = value; +// }, +// onSaved: (value) { +// model.description = value; +// }, +// ), +// 8.height, +// ], +// ).toShadowContainer(context, borderRadius: 20, padding: 12)) +// .expanded, +// FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), +// ], +// ), +// ), +// ); +// } +// +// ///Need to check which details show here... +// +// void _saveTap() async { +// if (!_formKey.currentState!.validate()) { +// return; +// } +// _formKey.currentState!.save(); +// log('payload ${model.toJson()}'); +// return; +// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); +// await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async { +// Navigator.pop(context); +// if (status) { +// Navigator.pop(context, true); +// } +// }); +// } +// } + import 'dart:developer'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -22,11 +245,16 @@ import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; class UpdateEndUserAssetDetailsView extends StatefulWidget { - EndUserAssetDetailsModel? assetDetailsModel; - String? costCenterName; - int? tableId; + final EndUserAssetDetailsModel? assetDetailsModel; + final String? costCenterName; + final int? tableId; - UpdateEndUserAssetDetailsView({Key? key, this.assetDetailsModel, this.costCenterName, this.tableId}) : super(key: key); + const UpdateEndUserAssetDetailsView({ + Key? key, + this.assetDetailsModel, + this.costCenterName, + this.tableId, + }) : super(key: key); @override State createState() => _UpdateEndUserAssetDetailsViewState(); @@ -34,147 +262,220 @@ class UpdateEndUserAssetDetailsView extends StatefulWidget { class _UpdateEndUserAssetDetailsViewState extends State { final GlobalKey _formKey = GlobalKey(); - final GlobalKey _scaffoldKey = GlobalKey(); - bool viewOnly = false; + late AssetDeliveryProvider assetDeliveryProvider; EndUserAssetDetailsModel model = EndUserAssetDetailsModel(); + late TextEditingController quantityController; late TextEditingController descriptionController; @override void initState() { + super.initState(); quantityController = TextEditingController(); descriptionController = TextEditingController(); + WidgetsBinding.instance.addPostFrameCallback((_) { - getInitialData(); + _loadInitialData(); }); - super.initState(); } - @override - void dispose() { - super.dispose(); - } - - void getInitialData() async { + void _loadInitialData() { assetDeliveryProvider = Provider.of(context, listen: false); + if (widget.assetDetailsModel != null) { - model = EndUserAssetDetailsModel.fromJson(widget.assetDetailsModel!.toJson()); + model = EndUserAssetDetailsModel.fromJson( + widget.assetDetailsModel!.toJson(), + ); model.costCenterName = widget.costCenterName; model.assetDeliveryExternalDeliveryId = widget.tableId; model.status = widget.assetDetailsModel?.status; model.rejectionReason = widget.assetDetailsModel?.rejectionReason; } + quantityController.text = model.rejectedQty != null ? model.rejectedQty.toString() : ''; descriptionController.text = model.description ?? ''; setState(() {}); } + bool get _isAccessory => model.type == 'Accessory'; + + bool get _isAccepted => model.status?.value == 1; + + bool get _isRejected => model.status?.value == 2; + + bool get _showRejectedQty { + if (_isAccessory) return true; + return false; + } + + bool get _showRejectionReason { + if (_isAccessory) { + if (_isRejected) return true; + if (_isAccepted && (model.rejectedQty ?? 0) > 0) return true; + return false; + } + if (_isRejected) return true; + return false; + } + @override Widget build(BuildContext context) { return Scaffold( - key: _scaffoldKey, appBar: DefaultAppBar( title: 'Item Details'.addTranslation, - titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + titleStyle: AppTextStyles.heading3.copyWith( + fontWeight: FontWeight.w500, + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + ), ), body: Form( key: _formKey, child: Column( children: [ SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Status'.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - initialValue: model.status, - onSelect: (status) { - if (status != null) { - model.status = status; - setState(() {}); - } - }, - ), - 8.height, - SingleItemDropDownMenu( - context: context, - height: 56.toScreenHeight, - title: 'Rejection Reason '.addTranslation, - titleTextColor: AppColor.neutral120, - showShadow: false, - backgroundColor: AppColor.fieldBgColor(context), - showAsBottomSheet: true, - initialValue: model.rejectionReason, - onSelect: (reason) { - if (reason != null) { - model.rejectionReason = reason; - setState(() {}); - } - }, - ), - 8.height, - if (model.type == 'Accessory') ...[ - AppTextFormField( - labelText: 'Rejected Quantity'.addTranslation, - controller: quantityController, - backgroundColor: AppColor.fieldBgColor(context), - textAlign: TextAlign.center, - labelStyle: AppTextStyles.textFieldLabelStyle, - textInputType: TextInputType.number, - showShadow: false, - onChange: (value) { - if (value.isNotEmpty) { - model.rejectedQty = model.rejectedQty = num.tryParse(value); - } - }, - style: Theme.of(context).textTheme.titleMedium, - ), - 8.height, - ], - AppTextFormField( - controller: descriptionController, - labelText: 'Description'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - labelStyle: AppTextStyles.textFieldLabelStyle, - alignLabelWithHint: true, - textInputType: TextInputType.multiline, - onChange: (value) { - model.description = value; - }, - onSaved: (value) { - model.description = value; - }, - ), - 8.height, - ], - ).toShadowContainer(context, borderRadius: 20, padding: 12)) - .expanded, - FooterActionButton.footerContainer(context: context, child: AppFilledButton(buttonColor: AppColor.primary10, label: 'Save'.addTranslation, maxWidth: true, onPressed: _saveTap)), + padding: const EdgeInsets.all(16), + child: _formBody(context), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: 'Save'.addTranslation, + maxWidth: true, + onPressed: _saveTap, + ), + ), ], ), ), ); } - ///Need to check which details show here... + Widget _formBody(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _statusDropdown(), + 8.height, + if (_showRejectedQty) ...[ + _rejectedQtyField(), + 8.height, + ], + if (_showRejectionReason) ...[ + _rejectionReasonDropdown(), + 8.height, + ], + _descriptionField(), + 8.height, + ], + ).toShadowContainer(context, borderRadius: 20, padding: 12); + } + + Widget _statusDropdown() { + return SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Status'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.status, + validator: (value) { + if (value == null) return 'Please select status'; + return null; + }, + onSelect: (status) { + if (status != null) { + model.status = status; + model.rejectionReason = null; + setState(() {}); + } + }, + ); + } + + Widget _rejectedQtyField() { + return AppTextFormField( + labelText: 'Rejected Quantity'.addTranslation, + controller: quantityController, + backgroundColor: AppColor.fieldBgColor(context), + textAlign: TextAlign.center, + labelStyle: AppTextStyles.textFieldLabelStyle, + textInputType: TextInputType.number, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + validator: (value) { + if (!_showRejectedQty) return null; + if ((value ?? '').isEmpty) return 'Mandatory'; + final qty = num.tryParse(value!); + if (qty == null || qty <= 0) return 'Enter valid quantity'; + return null; + }, + onChange: (value) { + model.rejectedQty = value.isNotEmpty ? num.tryParse(value) : null; + setState(() {}); + }, + ); + } + + Widget _rejectionReasonDropdown() { + return SingleItemDropDownMenu( + context: context, + height: 56.toScreenHeight, + title: 'Rejection Reason'.addTranslation, + titleTextColor: AppColor.neutral120, + showShadow: false, + backgroundColor: AppColor.fieldBgColor(context), + showAsBottomSheet: true, + initialValue: model.rejectionReason, + validator: (value) { + if (!_showRejectionReason) return null; + if (value == null) return 'Please select rejection reason'; + return null; + }, + onSelect: (reason) { + if (reason != null) { + model.rejectionReason = reason; + setState(() {}); + } + }, + ); + } + + Widget _descriptionField() { + return AppTextFormField( + controller: descriptionController, + labelText: 'Description'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onChange: (value) => model.description = value, + onSaved: (value) => model.description = value, + ); + } void _saveTap() async { + if (!_formKey.currentState!.validate()) return; + _formKey.currentState!.save(); - showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); - await assetDeliveryProvider.saveEndUserAssetDataData(model: model).then((status) async { - Navigator.pop(context); - if (status) { - Navigator.pop(context, true); - } - }); + log('payload ${model.toJson()}'); + + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const AppLazyLoading(), + ); + + final status = await assetDeliveryProvider.saveEndUserAssetDataData(model: model); + + Navigator.pop(context); + + if (status) { + Navigator.pop(context, true); + } } } diff --git a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart index 3b98beaa..1234a018 100644 --- a/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart +++ b/lib/modules/asset_delivery_module/pages/end_user_acceptance/update_end_user_cost_center_details_view.dart @@ -235,16 +235,6 @@ class _UpdateEndUserCostCenterDetailsViewState extends State const AppLazyLoading()); model.assetDeliveryExternalDetailId = widget.tableItemId; diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart index bb0b6ca9..be67dd74 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_child_asset_view.dart @@ -189,6 +189,39 @@ class _UpdateChildAssetViewState extends State { } }), 8.height, + AppTextFormField( + labelText: 'Asset Name'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.assetName, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Model'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.model, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Manufacturer'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.manufacturer ?? '', + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, AppTextFormField( labelText: 'Serial Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), @@ -423,6 +456,10 @@ class _UpdateChildAssetViewState extends State { } String _statusFromBool(bool? value) { - return value == true ? 'PASS' :value==false? 'FAIL':''; + return value == true + ? 'PASS' + : value == false + ? 'FAIL' + : ''; } } diff --git a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart index 8bac4319..52a14cda 100644 --- a/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart +++ b/lib/modules/asset_delivery_module/pages/technical_inpection/update_parent_asset_view.dart @@ -216,15 +216,55 @@ class _UpdateParentAssetViewState extends State { if (assetModel.site != null) { await provider.getSiteData(siteId: assetModel.site?.id, model: provider.parentFormModel); } - assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; - assetModel.id = 0; + assetModel.assetDeliveryInternalDetailAssetId = assetModel.id; + assetModel.id = 0; + if (assetModel.childAssetList != null && assetModel.childAssetList!.isNotEmpty) { + for (var asset in assetModel.childAssetList!) { + asset.assetDeliveryInternalDetailAssetChildId = asset.id; + asset.id = 0; + } + } provider.setParentModel(assetModel); log('child list length ${assetModel.childAssetList?.length}'); + populateTextFields(model: provider.parentFormModel); } } }), 8.height, + AppTextFormField( + labelText: 'Asset Name'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.assetName, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Model'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.model, + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + labelText: 'Manufacturer'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + initialValue: model.modelDefinition?.manufacturer ?? '', + textAlign: TextAlign.center, + enable: false, + labelStyle: AppTextStyles.textFieldLabelStyle, + showShadow: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, AppTextFormField( labelText: 'Serial Number'.addTranslation, backgroundColor: AppColor.fieldBgColor(context), diff --git a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart index c01a4c2c..6516b500 100644 --- a/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart +++ b/lib/modules/asset_delivery_module/provider/asset_delivery_provider.dart @@ -266,8 +266,7 @@ class AssetDeliveryProvider extends ChangeNotifier { "assetDeliveryExternalDeliveryId": tableItemId, "assetDeliveryExternalDetailId": lineId, "costCenters": list?.map((x) => x.toJson()).toList(), - if (serialNoList != null && serialNoList.isNotEmpty) - "serialNos": serialNoList.map((x) => x.toJson()).toList(), + if (serialNoList != null && serialNoList.isNotEmpty) "serialNos": serialNoList.map((x) => x.toJson()).toList(), }; try { final response = await ApiManager.instance.post(URLs.saveCostCenterAndSerialNoToLineDeliveryInspection, body: payload);