From e74f506be0ab69bc3b26e57cbdcd96d09f31abbe Mon Sep 17 00:00:00 2001 From: WaseemAbbasi22 Date: Wed, 9 Apr 2025 16:48:13 +0300 Subject: [PATCH] part avalibility ui implemented --- lib/controllers/api_routes/urls.dart | 9 +- lib/models/service_request/spare_parts.dart | 45 ++++++++++ .../service_request_detail_provider.dart | 38 ++++++++ .../components/activities_list_view.dart | 6 +- .../forms/spare_part/spare_part_request.dart | 90 ++++++++++++++++++- 5 files changed, 180 insertions(+), 8 deletions(-) diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 89e78aee..edc1bcfe 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -3,12 +3,12 @@ class URLs { static const String appReleaseBuildNumber = "14"; // 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 String _baseUrl = "$_host/mobile"; - static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis - // static final String _baseUrl = "$_host/mobile"; // host local UAT + // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis + static final String _baseUrl = "$_host/mobile"; // host local UAT // static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis static String _host = host1; @@ -159,6 +159,7 @@ class URLs { static get getAssetTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=500"; // get static get getPersonRoles => "$_baseUrl/Lookups/GetLookup?lookupEnum=36"; // get static get getPartNumber => "$_baseUrl/PartCatalog/GetPartAutoComplete"; // get + static get getSparePartAvailableQuantity => "$_baseUrl/SparePart/GetAvailablityQtyForSparePartByPartId"; // get static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=4"; // get static get getServiceReportDefectTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=601"; // get static get getCallRequestForWorkOrder => "$_baseUrl/CallRequest/GetCallRequestForWorkOrder"; // get diff --git a/lib/models/service_request/spare_parts.dart b/lib/models/service_request/spare_parts.dart index 11f183a9..8b4be559 100644 --- a/lib/models/service_request/spare_parts.dart +++ b/lib/models/service_request/spare_parts.dart @@ -76,3 +76,48 @@ class SparePart extends Base { return map; } } + +class StoreAvailability { + final int ?id; + final int? storeId; + final int ?availablityQty; + final String? siteName; + final String ?storeName; + final int? requestedQty; + final bool? alreadyRequestFromThisStore; + + StoreAvailability({ + this.id, + this.storeId, + this.availablityQty, + this.siteName, + this.storeName, + this.requestedQty, + this.alreadyRequestFromThisStore, + }); + + factory StoreAvailability.fromJson(Map json) { + return StoreAvailability( + id: json['id'] ?? 0, + storeId: json['storeId'] ?? 0, + availablityQty: json['availablityQty'] ?? 0, + siteName: json['siteName'] ?? '', + storeName: json['storeName'] ?? '', + requestedQty: json['requestedQty'] ?? 0, + alreadyRequestFromThisStore: json['alreadyRequestFromThisStore'] ?? false, + ); + } + + Map toJson() { + return { + 'id': id, + 'storeId': storeId, + 'availablityQty': availablityQty, + 'siteName': siteName, + 'storeName': storeName, + 'requestedQty': requestedQty, + 'alreadyRequestFromThisStore': alreadyRequestFromThisStore, + }; + } +} + diff --git a/lib/service_request_latest/service_request_detail_provider.dart b/lib/service_request_latest/service_request_detail_provider.dart index 7fa906f7..2902002b 100644 --- a/lib/service_request_latest/service_request_detail_provider.dart +++ b/lib/service_request_latest/service_request_detail_provider.dart @@ -14,6 +14,7 @@ import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_mo import 'package:test_sa/models/new_models/arrival_verification_type_model.dart'; import 'package:test_sa/models/new_models/dashboard_detail.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; import 'package:test_sa/models/service_request/supplier_details.dart'; import 'package:test_sa/service_request_latest/utilities/service_request_utils.dart'; @@ -104,6 +105,15 @@ class ServiceRequestDetailProvider extends ChangeNotifier { AssetRetiredHelperModel? assetRetiredHelperModel = AssetRetiredHelperModel(); ActivityMaintenanceHelperModel? activityMaintenanceHelperModel = ActivityMaintenanceHelperModel(); SparePartHelperModel? sparePartHelperModel; + List _storeAvailability= []; + + List get storeAvailability => _storeAvailability; + + set storeAvailability(List value) { + _storeAvailability = value; + notifyListeners(); + } + FixRemotelyHelperModel? fixRemotelyHelperModel = FixRemotelyHelperModel(); NeedVisitHelperModel? needVisitHelperModel = NeedVisitHelperModel(); NurseActionHelperModel? nurseActionHelperModel; @@ -242,6 +252,7 @@ class ServiceRequestDetailProvider extends ChangeNotifier { } } + //upload workorder attachment by engineer.. Future addWorkOrderAttachment({required int woId, required List attachments}) async { try { @@ -742,6 +753,33 @@ class ServiceRequestDetailProvider extends ChangeNotifier { } } + Future getStoreAvailabilityById({required num? partId}) async { + try { + isLoading = true; + notifyListeners(); + + final response = await ApiManager.instance.post( + URLs.getSparePartAvailableQuantity + "?PartId=$partId", + body: {}, + ); + + print('response i got is ${response.body}'); + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + final List data = json.decode(response.body)["data"]; + storeAvailability = data.map((item) => StoreAvailability.fromJson(item)).toList(); + } + + isLoading = false; + notifyListeners(); + } catch (e) { + log("getStoreAvalivility [error] : $e"); + isLoading = false; + notifyListeners(); + } + } + Future deleteActivitySparePart({required int id, required int workOrderId}) async { isLoading = true; notifyListeners(); diff --git a/lib/service_request_latest/views/components/activities_list_view.dart b/lib/service_request_latest/views/components/activities_list_view.dart index 94a70328..54b09a45 100644 --- a/lib/service_request_latest/views/components/activities_list_view.dart +++ b/lib/service_request_latest/views/components/activities_list_view.dart @@ -363,9 +363,9 @@ class _ActivitiesListViewState extends State { // ] ], ).toShadowContainer(context, padding: 12, showShadow: false).onPress(() { - if (requestDetailProvider.isReadOnlyRequest) { - // onEditMaintenanceRequestPress(context: context, requestDetailProvider: requestDetailProvider, activity: activity); - } + // if (requestDetailProvider.isReadOnlyRequest) { + // onEditMaintenanceRequestPress(context: context, requestDetailProvider: requestDetailProvider, activity: activity); + // } }); } diff --git a/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart index 44b105b8..8b1454a6 100644 --- a/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart +++ b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/parts_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; @@ -11,6 +12,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/helper_data_models/spare_part/activity_spare_part_model.dart'; import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/size_config.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/single_item_drop_down_menu.dart'; @@ -19,6 +21,7 @@ import 'package:test_sa/service_request_latest/service_request_detail_provider.d import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/views/widgets/images/new_multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import '../../../../../../models/service_request/spare_parts.dart'; import '../../../../../../new_views/common_widgets/app_text_form_field.dart'; @@ -119,6 +122,7 @@ class _SparePartRequestState extends State with TickerProvider key: _scaffoldKey, appBar: DefaultAppBar(title: context.translation.sparePartRequest), body: Consumer(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) { + print('data i got is ${requestDetailProvider.sparePartHelperModel?.sparePart?.toJson()}'); return SafeArea( child: Form( key: _formKey, @@ -155,7 +159,7 @@ class _SparePartRequestState extends State with TickerProvider loading: _isLoading, initialValue: requestDetailProvider.sparePartHelperModel?.sparePart, backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - onSelect: (part) { + onSelect: (part) async { if (part != null) { requestDetailProvider.sparePartHelperModel?.sparePart = part; _oracleNoController.text = part.oracleCode ?? ''; @@ -163,6 +167,36 @@ class _SparePartRequestState extends State with TickerProvider } }, ), + + if(requestDetailProvider.sparePartHelperModel?.sparePart?.id!=null)...[ + 12.height, + SizedBox( + height: 30.toScreenHeight, + child: Text('View Parts Availability',style:TextStyle( + fontSize: 12.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + color:AppColor.primary10 , + decorationColor: AppColor.primary10, + decoration: TextDecoration.underline, + )).onPress( + () async { + requestDetailProvider.getStoreAvailabilityById(partId: requestDetailProvider.sparePartHelperModel?.sparePart?.id); + showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + ), + ), + clipBehavior: Clip.antiAliasWithSaveLayer, + builder: (BuildContext context) => PartDetailBottomSheetSheet(), + ); + }, + ), + ), + ], 12.height, AppTextFormField( controller: _partQtyController, @@ -309,4 +343,58 @@ class _SparePartRequestState extends State with TickerProvider }), ); } + +} + + +class PartDetailBottomSheetSheet extends StatelessWidget { + + PartDetailBottomSheetSheet( {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: SizeConfig.screenHeight!/2.2, + width: SizeConfig.screenWidth, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 8.height, + 'Parts Availability'.heading6(context).paddingOnly(top: 12,start: 12), + Consumer( + builder: (context, requestDetailProvider,child) { + return requestDetailProvider.isLoading + ? const CircularProgressIndicator(color: AppColor.primary10).center + : requestDetailProvider.storeAvailability.isEmpty + ? const NoDataFound().center + : ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: requestDetailProvider.storeAvailability.length, + separatorBuilder: (czt, index) => 12.height, + itemBuilder: (context, index) { + StoreAvailability model = requestDetailProvider.storeAvailability[index]; + return partAvailableQuantityCard(context: context,model:model); + }, + ); + } + ).expanded, + ], + ), + ); + } + Widget partAvailableQuantityCard({required StoreAvailability model,required BuildContext context }){ + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 'Site Name: ${model.siteName??''}'.bodyText2(context).custom(color: AppColor.neutral120), + 8.height, + 'Store Name: ${model.storeName??''}'.bodyText2(context).custom(color: AppColor.neutral120), + 8.height, + 'Available Quantity: ${model.availablityQty??''}'.bodyText2(context).custom(color: AppColor.neutral120), + 8.height, + ] + ).toShadowContainer(context, padding: 12, showShadow: false,backgroundColor: AppColor.neutral110); + } }