diff --git a/frontend/mgramseva/lib/providers/common_provider.dart b/frontend/mgramseva/lib/providers/common_provider.dart new file mode 100644 index 000000000..cfe3730d2 --- /dev/null +++ b/frontend/mgramseva/lib/providers/common_provider.dart @@ -0,0 +1,951 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_share_me/flutter_share_me.dart'; +import 'package:mgramseva/model/bill/bill_payments.dart'; +import 'package:mgramseva/model/demand/demand_list.dart'; +import 'package:mgramseva/model/file/file_store.dart'; +import 'package:mgramseva/model/localization/language.dart'; +import 'package:mgramseva/model/localization/localization_label.dart'; +import 'package:mgramseva/model/mdms/payment_type.dart'; +import 'package:mgramseva/model/user/user_details.dart'; +import 'package:mgramseva/model/userProfile/user_profile.dart'; +import 'package:mgramseva/providers/language.dart'; +import 'package:mgramseva/repository/core_repo.dart'; +import 'package:mgramseva/routers/Routers.dart'; +import 'package:mgramseva/services/LocalStorage.dart'; +import 'package:mgramseva/services/MDMS.dart'; +import 'package:mgramseva/utils/Constants/I18KeyConstants.dart'; +import 'package:mgramseva/utils/Locilization/application_localizations.dart'; +import 'package:mgramseva/utils/constants.dart'; +import 'package:mgramseva/utils/date_formats.dart'; +import 'package:mgramseva/utils/error_logging.dart'; +import 'package:mgramseva/utils/global_variables.dart'; +import 'package:mgramseva/utils/loaders.dart'; +import 'package:mgramseva/utils/models.dart'; +import 'package:mgramseva/utils/notifyers.dart'; +import 'package:pdf/widgets.dart' as pw; +import 'package:provider/provider.dart'; +import 'package:universal_html/html.dart' as html; +import 'package:universal_html/html.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../model/demand/update_demand_list.dart'; + +class CommonProvider with ChangeNotifier { + List localizedStrings = []; + var userLoggedStreamCtrl = StreamController.broadcast(); + UserDetails? userDetails; + AppVersion? appVersion; + static Map downloadUrl = {}; + + dispose() { + userLoggedStreamCtrl.close(); + super.dispose(); + } + + Future> getLocalizationLabels() async { + var languageProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + List labels = []; + + dynamic localLabelResponse; + if (kIsWeb) { + localLabelResponse = + window.localStorage[languageProvider.selectedLanguage?.value ?? '']; + } else { + localLabelResponse = await storage.read( + key: languageProvider.selectedLanguage?.value ?? ''); + } + if (localLabelResponse != null && localLabelResponse.trim().isNotEmpty) { + return localizedStrings = jsonDecode(localLabelResponse) + .map((e) => LocalizationLabel.fromJson(e)) + .toList(); + } + + try { + var query = { + 'module': + 'mgramseva-common,mgramseva-consumer,mgramseva-expenses,mgramseva-water-connection,mgramseva-bill,mgramseva-payments,mgramseva-dashboard,mgramseva-feedback', + 'locale': languageProvider.selectedLanguage?.value ?? '', + 'tenantId': languageProvider.stateInfo!.code + }; + + var response = await CoreRepository().getLocilisation(query); + if (response != null) { + labels = localizedStrings = response; + setLocalizationLabels(response); + } + } catch (e) { + print(e); + } + return labels; + } + + setSelectedTenant(UserDetails? loginDetails) { + if (kIsWeb) { + window.localStorage[Constants.LOGIN_KEY] = + loginDetails == null ? '' : jsonEncode(loginDetails.toJson()); + } else { + storage.write( + key: Constants.LOGIN_KEY, + value: + loginDetails == null ? null : jsonEncode(loginDetails.toJson())); + } + } + + setTenant(tenant) { + userDetails?.selectedtenant = tenant; + setSelectedState(userDetails!); + notifyListeners(); + } + + void setSelectedState(UserDetails? loginDetails) async { + if (kIsWeb) { + window.localStorage[Constants.LOGIN_KEY] = + loginDetails == null ? '' : jsonEncode(loginDetails.toJson()); + } else { + storage.write( + key: Constants.LOGIN_KEY, + value: + loginDetails == null ? null : jsonEncode(loginDetails.toJson())); + } + } + + setLocalizationLabels(List labels) async { + var languageProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + try { + if (kIsWeb) { + window.localStorage[languageProvider.selectedLanguage?.value ?? ''] = + jsonEncode(labels.map((e) => e.toJson()).toList()); + } else { + await storage.write( + key: languageProvider.selectedLanguage?.value ?? '', + value: jsonEncode(labels.map((e) => e.toJson()).toList())); + } + } catch (e) { + Notifiers.getToastMessage(navigatorKey.currentState!.context, + 'Unable to store the details', 'ERROR'); + } + } + + set loginCredentails(UserDetails? loginDetails) { + userDetails = loginDetails; + if (kIsWeb) { + window.localStorage[Constants.LOGIN_KEY] = + loginDetails == null ? '' : jsonEncode(loginDetails.toJson()); + } else { + storage.write( + key: Constants.LOGIN_KEY, + value: + loginDetails == null ? null : jsonEncode(loginDetails.toJson())); + } + notifyListeners(); + } + + set userProfile(UserProfile? profile) { + if (kIsWeb) { + window.localStorage[Constants.USER_PROFILE_KEY] = + profile == null ? '' : jsonEncode(profile.toJson()); + } else { + storage.write( + key: Constants.USER_PROFILE_KEY, + value: profile == null ? null : jsonEncode(profile.toJson())); + } + notifyListeners(); + } + + walkThroughCondition(bool? firstTime, String key) { + if (kIsWeb) { + window.localStorage[key] = firstTime.toString(); + } else { + storage.write(key: key, value: firstTime.toString()); + } + notifyListeners(); + } + + Future getWalkThroughCheck(String key) async { + var userReposne; + try { + if (kIsWeb) { + userReposne = window.localStorage[key]; + } else { + userReposne = (await storage.read(key: key)); + } + } catch (e) { + userLoggedStreamCtrl.add(null); + } + if (userReposne == null) { + userReposne = 'false'; + } + return userReposne; + } + + Future getUserProfile() async { + var userReposne; + try { + if (kIsWeb) { + userReposne = window.localStorage[Constants.USER_PROFILE_KEY]; + } else { + userReposne = await storage.read(key: Constants.USER_PROFILE_KEY); + } + } catch (e) { + userLoggedStreamCtrl.add(null); + } + return UserProfile.fromJson(jsonDecode(userReposne)); + } + + Future getLoginCredentails() async { + var languageProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + dynamic loginResponse; + dynamic stateResponse; + try { + if (kIsWeb) { + loginResponse = window.localStorage[Constants.LOGIN_KEY]; + + stateResponse = window.localStorage[Constants.STATES_KEY]; + } else { + var isUpdated = false; + try { + if (!await storage.containsKey(key: Constants.APP_VERSION) || + !await storage.containsKey(key: Constants.BUILD_NUMBER)) { + await storage.deleteAll(); + isUpdated = true; + storage.write( + key: Constants.APP_VERSION, value: packageInfo?.version); + storage.write( + key: Constants.BUILD_NUMBER, value: packageInfo?.buildNumber); + } else { + if (await storage.read(key: Constants.APP_VERSION) != + packageInfo?.version || + await storage.read(key: Constants.BUILD_NUMBER) != + packageInfo?.buildNumber) { + await storage.deleteAll(); + isUpdated = true; + storage.write( + key: Constants.APP_VERSION, value: packageInfo?.version); + storage.write( + key: Constants.BUILD_NUMBER, value: packageInfo?.buildNumber); + } + } + } catch (e) {} + + if (!isUpdated) { + loginResponse = await storage.read(key: Constants.LOGIN_KEY); + stateResponse = await storage.read(key: Constants.STATES_KEY); + } + } + + if (stateResponse != null && stateResponse.trim().isNotEmpty) { + languageProvider.stateInfo = + StateInfo.fromJson(jsonDecode(stateResponse)); + } + + if (loginResponse != null && loginResponse.trim().isNotEmpty) { + var decodedResponse = UserDetails.fromJson(jsonDecode(loginResponse)); + userDetails = decodedResponse; + userLoggedStreamCtrl.add(decodedResponse); + } else { + userLoggedStreamCtrl.add(null); + } + } catch (e) { + userLoggedStreamCtrl.add(null); + } + } + + UserDetails? getWebLoginStatus() { + var languageProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + + dynamic loginResponse; + dynamic stateResponse; + + var isUpdated = false; + if (!window.localStorage.containsKey(Constants.APP_VERSION) || + !window.localStorage.containsKey(Constants.BUILD_NUMBER)) { + window.localStorage.clear(); + isUpdated = true; + window.localStorage[Constants.APP_VERSION] = packageInfo?.version ?? ''; + window.localStorage[Constants.BUILD_NUMBER] = + packageInfo?.buildNumber ?? ''; + } else { + if (window.localStorage[Constants.APP_VERSION] != packageInfo?.version || + window.localStorage[Constants.BUILD_NUMBER] != + packageInfo?.buildNumber) { + window.localStorage.clear(); + isUpdated = true; + window.localStorage[Constants.APP_VERSION] = packageInfo?.version ?? ''; + window.localStorage[Constants.BUILD_NUMBER] = + packageInfo?.buildNumber ?? ''; + } + } + + if (!isUpdated) { + loginResponse = window.localStorage[Constants.LOGIN_KEY]; + stateResponse = window.localStorage[Constants.STATES_KEY]; + } else { + userDetails = null; + } + + if (stateResponse != null && stateResponse.trim().isNotEmpty) { + languageProvider.stateInfo = + StateInfo.fromJson(jsonDecode(stateResponse)); + + if (languageProvider.stateInfo != null) { + ApplicationLocalizations(Locale( + languageProvider.selectedLanguage?.label ?? '', + languageProvider.selectedLanguage?.value)) + .load(); + } + } + + if (loginResponse != null && loginResponse.trim().isNotEmpty) { + var decodedResponse = UserDetails.fromJson(jsonDecode(loginResponse)); + userDetails = decodedResponse; + } + return userDetails; + } + + Future getAppVersionDetails() async { + try { + var localizationList = + await CoreRepository().getMdms(initRequestBody({"tenantId": "pb"})); + appVersion = localizationList.mdmsRes!.commonMasters!.appVersion!.first; + } catch (e) { + print(e.toString()); + } + } + + void onLogout() { + navigatorKey.currentState + ?.pushNamedAndRemoveUntil(Routes.SELECT_LANGUAGE, (route) => false); + loginCredentails = null; + } + + void onTapOfAttachment(FileStore store, context) async { + if (store.url == null) return; + CoreRepository().fileDownload(context, store.url!); + } + + void shareonwatsapp(FileStore store, mobileNumber, input) async { + if (store.url == null) return; + late html.AnchorElement anchorElement; + try { + var res = await CoreRepository().urlShotner(store.url as String); + if (kIsWeb) { + if (mobileNumber == null) { + anchorElement = new html.AnchorElement( + href: "https://wa.me/send?text=" + + input.toString().replaceFirst('{link}', res!)); + } else { + anchorElement = new html.AnchorElement( + href: "https://wa.me/+91$mobileNumber?text=" + + input.toString().replaceFirst('{link}', res!)); + } + + anchorElement.target = "_blank"; + anchorElement.click(); + } else { + var link; + if (mobileNumber == null) { + final FlutterShareMe flutterShareMe = FlutterShareMe(); + var response = await flutterShareMe.shareToWhatsApp( + msg: input.toString().replaceFirst('{link}', res!)) ?? + ''; + if (response.contains('PlatformException')) { + link = "https://api.whatsapp.com/send?text=" + + input + .toString() + .replaceAll(" ", "%20") + .replaceFirst('{link}', res); + await canLaunch(link) + ? launch(link) + : ErrorHandler.logError('failed to launch the url ${link}'); + } + return; + } else { + link = "https://wa.me/+91$mobileNumber?text=" + + input + .toString() + .replaceAll(" ", "%20") + .replaceFirst('{link}', res!); + } + await canLaunch(link) + ? launch(link) + : ErrorHandler.logError('failed to launch the url ${link}'); + } + } catch (e, s) { + ErrorHandler.logError(e.toString(), s); + } + } + + void getStoreFileDetails( + fileStoreId, mode, mobileNumber, context, link) async { + if (fileStoreId == null) return; + try { + var res = await CoreRepository().fetchFiles([fileStoreId!]); + if (res != null) { + if (mode == 'Share') { + shareonwatsapp(res.first, mobileNumber, link); + } else + onTapOfAttachment(res.first, context); + } + } catch (e, s) { + ErrorHandler.logError(e.toString(), s); + } + } + + void getFileFromPDFPaymentService( + body, params, mobileNumber, Payments payments, mode) async { + try { + var res = await CoreRepository().getFileStorefromPdfService(body, params); + String link = (ApplicationLocalizations.of(navigatorKey.currentContext!) + .translate(i18.common.SHARE_RECEIPT_LINK) + .toString() + .replaceFirst('{user}', payments.paidBy!) + .replaceFirst('{Amount}', payments.totalAmountPaid.toString()) + .replaceFirst('{new consumer id}', + payments.paymentDetails!.first.bill!.consumerCode.toString()) + .replaceFirst('{Amount}', + (payments.totalDue! - payments.totalAmountPaid!).toString())); + getStoreFileDetails(res!.filestoreIds!.first, mode, mobileNumber, + navigatorKey.currentContext, link); + } catch (e, s) { + ErrorHandler.logError(e.toString(), s); + } + } + + void getFileFromPDFBillService( + body, + params, + mobileNumber, + bill, + mode, + ) async { + try { + var res = await CoreRepository().getFileStorefromPdfService(body, params); + + String link = (ApplicationLocalizations.of(navigatorKey.currentContext!) + .translate(i18.common.SHARE_BILL_LINK) + .toString() + .replaceFirst('{user}', bill.payerName!.toString()) + .replaceFirst('{cycle}', + '${DateFormats.getMonthWithDay(bill.billDetails?.first?.fromPeriod)} - ${DateFormats.getMonthWithDay(bill.billDetails?.first?.toPeriod)}') + .replaceFirst('{new consumer id}', bill.consumerCode!.toString()) + .replaceFirst('{Amount}', bill.totalAmount.toString())); + getStoreFileDetails( + res!.filestoreIds!.first, + mode, + mobileNumber, + navigatorKey.currentContext, + link, + ); + } catch (e, s) { + ErrorHandler.logError(e.toString(), s); + } + } + + String? getMdmsId(LanguageList? mdms, String code, MDMSType mdmsType) { + try { + switch (mdmsType) { + case MDMSType.BusinessService: + return mdms?.mdmsRes?.billingService?.businessServiceList + ?.firstWhere((e) => e.businessService == code) + .code; + case MDMSType.ConsumerType: + return mdms?.mdmsRes?.billingService?.businessServiceList + ?.firstWhere((e) => e.businessService == code) + .code; + case MDMSType.TaxHeadCode: + return mdms?.mdmsRes?.billingService?.taxHeadMasterList + ?.firstWhere((e) => e.service == code) + .code; + default: + return ''; + } + } catch (e) { + return ''; + } + } + + Future sharePdfOnWhatsApp(BuildContext context, pw.Document pdf, + String fileName, String localizedText, + {bool isDownload = false}) async { + try { + if (isDownload && kIsWeb) { + final blob = html.Blob([await pdf.save()]); + final url = html.Url.createObjectUrlFromBlob(blob); + final anchor = html.document.createElement('a') as html.AnchorElement + ..href = url + ..style.display = 'none' + ..download = '$fileName.pdf'; + html.document.body?.children.add(anchor); + anchor.click(); + html.document.body?.children.remove(anchor); + html.Url.revokeObjectUrl(url); + } else { + /// Enable loader + Loaders.showLoadingDialog(context, label: ''); + + Uint8List data = await pdf.save(); + + /// Uploading file to S3 bucket + var file = CustomFile(data, fileName, 'pdf'); + var response = await CoreRepository() + .uploadFiles([file], APIConstants.API_MODULE_NAME); + + if (response.isNotEmpty) { + var commonProvider = + Provider.of(context, listen: false); + var res = + await CoreRepository().fetchFiles([response.first.fileStoreId!]); + if (res != null && res.isNotEmpty) { + if (isDownload) { + CoreRepository().fileDownload(context, res.first.url ?? ''); + } else { + var url = res.first.url ?? ''; + if (url.contains(',')) { + url = url.split(',').first; + } + response.first.url = url; + + commonProvider.shareonwatsapp( + response.first, null, localizedText); + } + } + } + navigatorKey.currentState?.pop(); + } + } catch (e, s) { + navigatorKey.currentState?.pop(); + ErrorHandler().allExceptionsHandler(context, e, s); + } + } + + Future getPdfFontFamily() async { + var language = Provider.of(navigatorKey.currentContext!, + listen: false); + + switch (language.selectedLanguage!.value) { + case 'en_IN': + return pw.Font.ttf( + await rootBundle.load('assets/fonts/Roboto/Roboto-Regular.ttf')); + case 'hi_IN': + return pw.Font.ttf( + await rootBundle.load('assets/fonts/Roboto/Hind-Regular.ttf')); + default: + return pw.Font.ttf( + await rootBundle.load('assets/fonts/Roboto/punjabi.ttf')); + } + } + + // static String getAdvanceAdjustedAmount(List demandList) { + // var amount = '0'; + // var index = -1; + // for(int i =0; i < demandList.length; i++){ + // index = demandList[i].demandDetails?.lastIndexWhere((e) => e.taxHeadMasterCode == 'WS_ADVANCE_CARRYFORWARD') ?? -1; + // if(index != -1){ + // + // if(demandList[i].demandDetails?.length == 1){ + // + // }else if(demandList[i].demandDetails?.length == 2){ + // amount = (demandList[i].demandDetails![index].collectionAmount ?? 0).toString(); + // } else if(demandList[i].demandDetails?[index].collectionAmount == demandList[i].demandDetails?[index].taxAmount){ + // if((demandList.first.demandDetails?.first.collectionAmount ?? 0) > 0){ + // amount = (-(demandList.first.demandDetails!.first.collectionAmount ?? 0)).toString(); + // }else { + // amount = (demandList[i].demandDetails![index].collectionAmount ?? 0).toString(); + // } + // } + // else{ + // amount = ((demandList[i].demandDetails![index].collectionAmount ?? 0) - (demandList[i].demandDetails![index-1].collectionAmount ?? 0)).toString(); + // } + // break; + // } + // } + // return amount; + // } + + static String getAdvanceAdjustedAmount(List demandList) { + var amount = '0.0'; + var index = -1; + + if (demandList.isEmpty) return amount; + + var filteredDemands = + demandList.where((e) => !(e.isPaymentCompleted ?? false)).toList(); + if (filteredDemands.first.demandDetails?.first.taxHeadMasterCode == + 'WS_TIME_PENALTY' && + CommonProvider.getPenaltyApplicable(demandList).penaltyApplicable != + 0) { + return amount; + } else { + for (int i = 0; i < filteredDemands.length; i++) { + index = demandList[i].demandDetails?.lastIndexWhere( + (e) => e.taxHeadMasterCode == 'WS_ADVANCE_CARRYFORWARD') ?? + -1; + + if (index != -1) { + var demandDetail = demandList[i].demandDetails?[index]; + if (demandDetail!.collectionAmount!.abs() < + demandDetail.taxAmount!.abs()) { + amount = filteredDemands.first.demandDetails?.last.collectionAmount + ?.toString() ?? + '0.0'; + } else if (demandDetail.collectionAmount! == + demandDetail.taxAmount!) { + if (filteredDemands.first.demandDetails?.last.collectionAmount != + 0) { + var list = []; + for (int j = 0; j <= i; j++) { + for (int k = 0; + k < (filteredDemands[j].demandDetails?.length ?? 0); + k++) { + if (k == index && j == i) break; + list.add( + filteredDemands[j].demandDetails![k].collectionAmount ?? + 0); + } + } + var collectedAmount = list.reduce((a, b) => a + b); + amount = double.parse("$collectedAmount") >= + double.parse("${demandDetail.collectionAmount?.abs()}") + ? filteredDemands.first.demandDetails?.last.collectionAmount + ?.toString() ?? + '0.0' + : '0.0'; + } + } + } + } + } + return amount; + } + + static double getTotalBillAmount(List demandList) { + if (!isFirstDemand(demandList)) { + var amount = 0.0; + demandList.first.demandDetails?.forEach((demand) { + if (demand.taxHeadMasterCode == '10102' || + demand.taxHeadMasterCode == '10201' || + demand.taxHeadMasterCode == 'WS_TIME_PENALTY') + amount += ((demand.taxAmount ?? 0) - (demand.collectionAmount ?? 0)); + }); + return amount; + } + return ((CommonProvider.checkAdvance(demandList) + ? (demandList.first.demandDetails?.first.taxAmount ?? 0) + : (demandList.first.demandDetails?.first.taxAmount ?? 0) - + (demandList.first.demandDetails?.first.collectionAmount ?? 0)) + + CommonProvider.getArrearsAmount(demandList)); + } + + static num getNetDueAmountWithWithOutPenalty(num totalAmount, Penalty penalty, + [bool withPenalty = false]) { + if (withPenalty) + return totalAmount >= 0 + ? (penalty.isDueDateCrossed + ? totalAmount + : totalAmount + penalty.penalty) + : penalty.penalty; + return totalAmount >= 0 ? (totalAmount) : 0.0; + } + + static bool isFirstDemand(List demandList) { + var isFirstDemand = false; + + if (demandList.isEmpty == true) { + isFirstDemand = false; + } else if (demandList.length == 1 && + demandList.first.consumerType == 'waterConnection-arrears') { + isFirstDemand = false; + } else if (demandList.length == 1 && + demandList.first.consumerType == 'waterConnection-advance' && + demandList.first.demandDetails?.first.taxHeadMasterCode == + 'WS_ADVANCE_CARRYFORWARD') { + isFirstDemand = false; + } else { + isFirstDemand = true; + } + return isFirstDemand; + } + + static double getNormalPenalty(List demandList) { + var penalty = 0.0; + + var filteredDemands = + demandList.where((e) => !(e.isPaymentCompleted ?? false)).toList(); + + filteredDemands.forEach((billDetails) { + billDetails.demandDetails?.forEach((billAccountDetails) { + if (billAccountDetails.taxHeadMasterCode == '10201') { + penalty += ((billAccountDetails.taxAmount ?? 0) - + (billAccountDetails.collectionAmount ?? 0)); + } + }); + }); + return penalty; + } + + static double getCurrentBill(List demandList) { + var currentBill = 0.0; + var currentBillLeft = 0.0; + + var filteredDemands = + demandList.where((e) => !(e.isPaymentCompleted ?? false)); + + filteredDemands.forEach((elem) { + elem.demandDetails?.forEach((demand) { + if (demand.taxHeadMasterCode == '10101') { + currentBillLeft = + ((demand.taxAmount ?? 0) - (demand.collectionAmount ?? 0)); + } + }); + }); + + if (currentBillLeft == 0) { + filteredDemands.first.demandDetails?.forEach((billAccountDetails) { + if (billAccountDetails.taxHeadMasterCode == '10101') { + currentBill += ((billAccountDetails.taxAmount ?? 0) - + (billAccountDetails.collectionAmount ?? 0)); + } + }); + } else { + currentBill = currentBillLeft; + } + + return currentBill; + } + + static Penalty getPenalty(List? demandList) { + Penalty? penalty; + + var filteredDemands = + demandList?.where((e) => !(e.isPaymentCompleted ?? false)).first; + + filteredDemands?.demandDetails?.forEach((billAccountDetails) { + if (billAccountDetails.taxHeadMasterCode == 'WS_TIME_PENALTY') { + var amount = billAccountDetails.taxAmount ?? 0; + DateTime billGenerationDate, expiryDate; + // DateTime.fromMillisecondsSinceEpoch(1659420829000); + var date = billAccountDetails.auditDetails != null + ? DateTime.fromMillisecondsSinceEpoch( + billAccountDetails.auditDetails!.createdTime ?? 0) + : DateTime.fromMillisecondsSinceEpoch(filteredDemands + .demandDetails?.first.auditDetails!.createdTime ?? + 0); + billGenerationDate = + expiryDate = DateTime(date.year, date.month, date.day); + expiryDate = expiryDate.add(Duration( + milliseconds: filteredDemands.billExpiryTime ?? 0, days: 0)); + penalty = Penalty( + amount.toDouble(), + DateFormats.getFilteredDate(expiryDate.toString()), + DateTime.now().isAfter(expiryDate)); + } + }); + return penalty ?? Penalty(0.0, '', false); + } + + static PenaltyApplicable getPenaltyApplicable(List? demandList) { + var res = []; + var filteredDemands = + demandList?.where((e) => !(e.isPaymentCompleted ?? false)).toList(); + + if (demandList?.first.demandDetails?.first.taxHeadMasterCode == + 'WS_TIME_PENALTY') { + filteredDemands?.first.demandDetails!.forEach((e) { + if (e.taxHeadMasterCode == 'WS_TIME_PENALTY') { + res.add((e.taxAmount ?? 0) - (e.collectionAmount ?? 0)); + } + }); + } else { + filteredDemands?.first.demandDetails!.forEach((e) { + if (e.taxHeadMasterCode == 'WS_TIME_PENALTY' || + e.taxHeadMasterCode == '10201') { + res.add((e.taxAmount ?? 0) - (e.collectionAmount ?? 0)); + } + }); + } + + var penaltyAmount = res.length == 0 + ? 0 + : ((res.reduce((previousValue, element) => previousValue + element)) + as double) + .abs(); + + return PenaltyApplicable(penaltyAmount.toDouble()); + } + + static num getAdvanceAmount(List demandList) { + var amount = 0.0; + var index = -1; + for (int i = 0; i < demandList.length; i++) { + index = demandList[i].demandDetails?.lastIndexWhere( + (e) => e.taxHeadMasterCode == 'WS_ADVANCE_CARRYFORWARD') ?? + -1; + if (index != -1) { + amount = (demandList[i].demandDetails![index].taxAmount ?? 0) - + (demandList[i].demandDetails![index].collectionAmount ?? 0); + break; + } + } + return amount; + } + + static double getArrearsAmount(List demandList) { + List res = []; + + if (!isFirstDemand(demandList)) { + var arrearsAmount = 0.0; + demandList.first.demandDetails?.forEach((demand) { + if (demand.taxHeadMasterCode == '10102') + arrearsAmount += + ((demand.taxAmount ?? 0) - (demand.collectionAmount ?? 0)); + }); + return arrearsAmount; + } + + if (demandList.isNotEmpty) { + var filteredDemands = demandList + .where((e) => + (!(e.isPaymentCompleted ?? false) && e.status != 'CANCELLED')) + .toList(); + for (var demand in filteredDemands) { + demand.demandDetails!.forEach((e) { + if (e.taxHeadMasterCode != 'WS_ADVANCE_CARRYFORWARD') { + res.add((e.taxAmount ?? 0) - (e.collectionAmount ?? 0)); + } + }); + } + } + + var arrearsDeduction = + (demandList.first.demandDetails?.first.taxHeadMasterCode != + 'WS_ADVANCE_CARRYFORWARD' && + demandList.first.demandDetails?.first.taxHeadMasterCode != + 'WS_TIME_PENALTY') + ? ((demandList.first.demandDetails?.first.taxAmount ?? 0) - + (demandList.first.demandDetails?.first.collectionAmount ?? 0)) + : 0; + + return res.length == 0 + ? 0 + : ((res.reduce((previousValue, element) => previousValue + element) - + arrearsDeduction) as double) + .abs(); + } + + static double getArrearsAmountOncePenaltyExpires(List demandList) { + List res = []; + var arrearsDeduction = 0.0; + var penaltyDeduction = 0.0; + + if (!isFirstDemand(demandList)) { + var arrearsAmount = 0.0; + demandList.first.demandDetails?.forEach((demand) { + if (demand.taxHeadMasterCode == '10102') + arrearsAmount += + ((demand.taxAmount ?? 0) - (demand.collectionAmount ?? 0)); + }); + return arrearsAmount; + } + + if (demandList.isNotEmpty) { + var filteredDemands = demandList + .where((e) => + (!(e.isPaymentCompleted ?? false) && e.status != 'CANCELLED')) + .toList(); + + filteredDemands.forEach((elem) { + elem.demandDetails?.forEach((element) { + if (element.taxHeadMasterCode == '10101') { + arrearsDeduction = + ((element.taxAmount ?? 0) - (element.collectionAmount ?? 0)); + } + }); + }); + + filteredDemands.first.demandDetails?.forEach((element) { + if (element.taxHeadMasterCode == 'WS_TIME_PENALTY') { + penaltyDeduction = + ((element.taxAmount ?? 0) - (element.collectionAmount ?? 0)); + } + }); + + for (var demand in filteredDemands) { + demand.demandDetails!.forEach((e) { + if (e.taxHeadMasterCode != 'WS_ADVANCE_CARRYFORWARD') { + res.add((e.taxAmount ?? 0) - (e.collectionAmount ?? 0)); + } + }); + } + } + + return res.length == 0 + ? 0 + : ((res.reduce((previousValue, element) => previousValue + element) - + arrearsDeduction - + penaltyDeduction) as double) + .abs(); + } + + static Future getMdmsBillingService() async { + try { + var commonProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + + return await CoreRepository().getPaymentTypeMDMS(getMdmsPaymentModes( + commonProvider.userDetails!.selectedtenant?.code.toString() ?? + commonProvider.userDetails!.userRequest!.tenantId.toString())); + } catch (e) { + return PaymentType(); + } + } + + static bool checkAdvance(List demandList) { + var advance = false; + var index = -1; + for (int i = 0; i < demandList.length; i++) { + index = demandList[i].demandDetails?.lastIndexWhere( + (e) => e.taxHeadMasterCode == 'WS_ADVANCE_CARRYFORWARD') ?? + -1; + if (index != -1) { + advance = true; + break; + } + } + return advance; + } + + static bool getPenaltyOrAdvanceStatus(PaymentType? languageList, + [isAdvance = false, bool isTimePenalty = false]) { + if (languageList == null) return false; + var index = languageList.mdmsRes?.billingService?.taxHeadMasterList + ?.indexWhere((e) => + e.code == + (isAdvance + ? 'WS_ADVANCE_CARRYFORWARD' + : isTimePenalty + ? 'WS_TIME_PENALTY' + : '10201')); + if (index != null && index != -1) { + return (languageList + .mdmsRes?.billingService?.taxHeadMasterList?[index].isRequired ?? + false); + } + return false; + } +} diff --git a/frontend/mgramseva/lib/providers/household_register_provider.dart b/frontend/mgramseva/lib/providers/household_register_provider.dart new file mode 100644 index 000000000..d5c827609 --- /dev/null +++ b/frontend/mgramseva/lib/providers/household_register_provider.dart @@ -0,0 +1,405 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:mgramseva/model/connection/water_connection.dart'; +import 'package:mgramseva/model/connection/water_connections.dart'; +import 'package:mgramseva/providers/common_provider.dart'; +import 'package:mgramseva/repository/search_connection_repo.dart'; +import 'package:mgramseva/routers/Routers.dart'; +import 'package:mgramseva/screeens/HouseholdRegister/household_pdf.dart'; +import 'package:mgramseva/utils/Constants/I18KeyConstants.dart'; +import 'package:mgramseva/utils/ExcelDownload/generate_excel.dart'; +import 'package:mgramseva/utils/Locilization/application_localizations.dart'; +import 'package:mgramseva/utils/constants.dart'; +import 'package:mgramseva/utils/error_logging.dart'; +import 'package:mgramseva/utils/global_variables.dart'; +import 'package:mgramseva/utils/loaders.dart'; +import 'package:mgramseva/utils/models.dart'; +import 'package:provider/provider.dart'; + +class HouseholdRegisterProvider with ChangeNotifier { + var streamController = StreamController.broadcast(); + TextEditingController searchController = TextEditingController(); + int offset = 1; + int limit = 10; + late DateTime selectedDate; + SortBy? sortBy; + WaterConnections? waterConnectionsDetails; + WaterConnection? waterConnection; + String selectedTab = Constants.ALL; + Map collectionCountHolder = {}; + Timer? debounce; + bool isLoaderEnabled = false; + @override + void dispose() { + streamController.close(); + super.dispose(); + } + + onChangeOfTab(BuildContext context, int index) async { + var householdProvider = + Provider.of(context, listen: false) + ..limit = 10 + ..offset = 1 + ..sortBy = SortBy('connectionNumber', false); + + householdProvider + ..waterConnectionsDetails?.waterConnection = [] + ..waterConnectionsDetails?.totalCount = null; + + if (index == 0) { + householdProvider.selectedTab = Constants.ALL; + } else if (index == 1) { + householdProvider.selectedTab = Constants.PAID; + } else { + householdProvider.selectedTab = Constants.PENDING; + } + householdProvider.fetchHouseholdDetails( + context, householdProvider.limit, householdProvider.offset, true); + } + + Future fetchHouseholdDetails( + BuildContext context, int limit, int offSet, + [bool isSearch = false]) async { + var commonProvider = Provider.of(context, listen: false); + var totalCount = waterConnectionsDetails?.totalCount ?? 0; + this.limit = limit; + this.offset = offSet; + notifyListeners(); + if (!isSearch && + waterConnectionsDetails?.totalCount != null && + ((offSet + limit) > totalCount ? totalCount : (offSet + limit)) <= + (waterConnectionsDetails?.waterConnection?.length ?? 0)) { + streamController.add(waterConnectionsDetails?.waterConnection?.sublist( + offset - 1, + ((offset + limit) - 1) > totalCount + ? totalCount + : (offset + limit) - 1)); + return; + } + + if (isSearch) waterConnectionsDetails = null; + + var query = { + 'tenantId': commonProvider.userDetails?.selectedtenant?.code, + 'offset': '${offset - 1}', + 'limit': '$limit', + 'toDate': '${DateTime.now().millisecondsSinceEpoch}', + 'isCollectionCount': 'true', + }; + + if (selectedTab != Constants.ALL) { + query.addAll( + {'isBillPaid': (selectedTab == Constants.PAID) ? 'true' : 'false'}); + } + + if (sortBy != null) { + query.addAll({ + 'sortOrder': sortBy!.isAscending ? 'ASC' : 'DESC', + 'sortBy': sortBy!.key + }); + } + + if (searchController.text.trim().isNotEmpty) { + query.addAll({ + 'textSearch': searchController.text.trim(), + // 'name' : searchController.text.trim(), + 'freeSearch': 'true', + }); + } + + query + .removeWhere((key, value) => (value is String && value.trim().isEmpty)); + streamController.add(null); + + isLoaderEnabled = true; + notifyListeners(); + try { + var response = await SearchConnectionRepository().getconnection(query); + + var searchResponse; + if (isSearch && selectedTab != Constants.ALL) { + query.remove('isBillPaid'); + searchResponse = + await SearchConnectionRepository().getconnection(query); + } + + isLoaderEnabled = false; + + if (response != null) { + if (selectedTab == Constants.ALL) { + collectionCountHolder[Constants.ALL] = response.totalCount ?? 0; + collectionCountHolder[Constants.PAID] = + response.collectionDataCount?.collectionPaid ?? 0; + collectionCountHolder[Constants.PENDING] = + response.collectionDataCount?.collectionPending ?? 0; + } else if (searchResponse != null) { + collectionCountHolder[Constants.ALL] = searchResponse.totalCount ?? 0; + collectionCountHolder[Constants.PAID] = + searchResponse.collectionDataCount?.collectionPaid ?? 0; + collectionCountHolder[Constants.PENDING] = + searchResponse.collectionDataCount?.collectionPending ?? 0; + } + + if (waterConnectionsDetails == null) { + waterConnectionsDetails = response; + notifyListeners(); + } else { + waterConnectionsDetails?.totalCount = response.totalCount; + waterConnectionsDetails?.waterConnection + ?.addAll(response.waterConnection ?? []); + } + notifyListeners(); + streamController.add(waterConnectionsDetails!.waterConnection!.isEmpty + ? [] + : waterConnectionsDetails?.waterConnection?.sublist( + offSet - 1, + ((offset + limit - 1) > + (waterConnectionsDetails?.totalCount ?? 0)) + ? (waterConnectionsDetails!.totalCount!) + : (offset + limit) - 1)); + } + } catch (e, s) { + isLoaderEnabled = false; + notifyListeners(); + streamController.addError('error'); + ErrorHandler().allExceptionsHandler(context, e, s); + } + } + + List getCollectionsTabList(BuildContext context) { + var list = [i18.dashboard.ALL, i18.dashboard.PAID, i18.dashboard.PENDING]; + return List.generate( + list.length, + (index) => + '${ApplicationLocalizations.of(context).translate(list[index])} (${getCollectionsCount(index)})'); + } + + bool isTabSelected(int index) { + if (selectedTab == Constants.ALL && index == 0) return true; + if ((selectedTab == Constants.PENDING && index == 2) || + (selectedTab == Constants.PAID && index == 1)) return true; + return false; + } + + List get collectionHeaderList => [ + TableHeader(i18.common.CONNECTION_ID, + isSortingRequired: true, + isAscendingOrder: + sortBy != null && sortBy!.key == 'connectionNumber' + ? sortBy!.isAscending + : null, + apiKey: 'connectionNumber', + callBack: onSort), + TableHeader(i18.common.NAME, + isSortingRequired: false, + isAscendingOrder: sortBy != null && sortBy!.key == 'name' + ? sortBy!.isAscending + : null, + apiKey: 'name', + callBack: onSort), + TableHeader(i18.consumer.FATHER_SPOUSE_NAME, + isSortingRequired: false, + isAscendingOrder: + sortBy != null && sortBy!.key == 'fatherOrHusbandName' + ? sortBy!.isAscending + : null, + apiKey: 'fatherOrHusbandName', + callBack: onSort), + TableHeader(i18.householdRegister.PENDING_COLLECTIONS, + isSortingRequired: true, + isAscendingOrder: + sortBy != null && sortBy!.key == 'collectionPendingAmount' + ? sortBy!.isAscending + : null, + apiKey: 'collectionPendingAmount', + callBack: onSort), + ]; + + List getCollectionsData(List list) { + return list.map((e) => getCollectionRow(e)).toList(); + } + + getDownloadList() { + return collectionCountHolder[selectedTab] ?? 0; + } + + int getCollectionsCount(int index) { + switch (index) { + case 0: + return collectionCountHolder[Constants.ALL] ?? 0; + case 1: + return collectionCountHolder[Constants.PAID] ?? 0; + case 2: + return collectionCountHolder[Constants.PENDING] ?? 0; + default: + return 0; + } + } + + String? truncateWithEllipsis(String? myString) { + return (myString!.length <= 20) + ? myString + : '${myString.substring(0, 20)}...'; + } + + TableDataRow getCollectionRow(WaterConnection connection) { + String? name = + truncateWithEllipsis(connection.connectionHolders?.first.name); + String? fatherName = truncateWithEllipsis( + connection.connectionHolders?.first.fatherOrHusbandName); + return TableDataRow([ + TableData( + '${connection.connectionNo?.split('/').first ?? ''}/...${connection.connectionNo?.split('/').last ?? ''} ${connection.connectionType == 'Metered' ? '- M' : ''}', + callBack: onClickOfCollectionNo, + apiKey: connection.connectionNo), + TableData('${name ?? ''}'), + TableData('${fatherName ?? ''}'), + TableData( + '${connection.additionalDetails?.collectionPendingAmount != null ? double.parse(connection.additionalDetails?.collectionPendingAmount ?? '') < 0.0 ? '- ₹ ${double.parse(connection.additionalDetails?.collectionPendingAmount ?? '').abs()}' : ' ₹ ${connection.additionalDetails?.collectionPendingAmount}' : '-'}'), + ]); + } + + onClickOfCollectionNo(TableData tableData) { + var waterConnection = waterConnectionsDetails?.waterConnection + ?.firstWhere((element) => element.connectionNo == tableData.apiKey); + Navigator.pushNamed(navigatorKey.currentContext!, Routes.HOUSEHOLD_DETAILS, + arguments: { + 'waterconnections': waterConnection, + 'mode': 'collect', + 'status': waterConnection?.status + }); + } + + onSort(TableHeader header) { + if (sortBy != null && sortBy!.key == header.apiKey) { + header.isAscendingOrder = !sortBy!.isAscending; + } else if (header.isAscendingOrder == null) { + header.isAscendingOrder = true; + } else { + header.isAscendingOrder = !(header.isAscendingOrder ?? false); + } + sortBy = SortBy(header.apiKey ?? '', header.isAscendingOrder!); + notifyListeners(); + fetchHouseholdDetails(navigatorKey.currentContext!, limit, 1, true); + } + + void onSearch(String val, BuildContext context) { + if (debounce?.isActive ?? false) debounce?.cancel(); + debounce = Timer(const Duration(milliseconds: 500), () { + fetchDetails(context, limit, 1, true); + }); + } + + void onChangeOfPageLimit(PaginationResponse response, BuildContext context) { + fetchDetails( + context, response.limit, response.offset, response.isPageChange); + } + + fetchDetails(BuildContext context, + [int? localLimit, int? localOffSet, bool isSearch = false]) { + if (isLoaderEnabled) return; + + fetchHouseholdDetails( + context, localLimit ?? limit, localOffSet ?? 1, isSearch); + } + + void createExcelOrPdfForAllConnections(BuildContext context, bool isDownload, + {bool isExcelDownload = false}) async { + var commonProvider = Provider.of( + navigatorKey.currentContext!, + listen: false); + WaterConnections? waterConnectionsDetails; + + var query = { + 'tenantId': commonProvider.userDetails?.selectedtenant?.code, + 'limit': '-1', + 'toDate': '${DateTime.now().millisecondsSinceEpoch}', + 'isCollectionCount': 'true', + }; + + if (selectedTab != Constants.ALL) { + query.addAll( + {'isBillPaid': (selectedTab == Constants.PAID) ? 'true' : 'false'}); + } + + if (sortBy != null) { + query.addAll({ + 'sortOrder': sortBy!.isAscending ? 'ASC' : 'DESC', + 'sortBy': sortBy!.key + }); + } + + if (searchController.text.trim().isNotEmpty) { + query.addAll({ + 'textSearch': searchController.text.trim(), + // 'name' : searchController.text.trim(), + 'freeSearch': 'true', + }); + } + + query + .removeWhere((key, value) => (value is String && value.trim().isEmpty)); + + Loaders.showLoadingDialog(context); + try { + waterConnectionsDetails = + await SearchConnectionRepository().getconnection(query); + + Navigator.pop(context); + } catch (e, s) { + Navigator.pop(context); + ErrorHandler().allExceptionsHandler(context, e, s); + return; + } + + if (waterConnectionsDetails.waterConnection == null || + waterConnectionsDetails.waterConnection!.isEmpty) return; + + var headerList = [ + i18.common.CONNECTION_ID, + i18.common.NAME, + i18.consumer.FATHER_SPOUSE_NAME, + i18.householdRegister.PENDING_COLLECTIONS + ]; + + var tableData = waterConnectionsDetails.waterConnection + ?.map>((connection) => [ + '${connection.connectionNo ?? ''} ${connection.connectionType == 'Metered' ? '- M' : ''}', + '${connection.connectionHolders?.first.name ?? ''}', + '${connection.connectionHolders?.first.fatherOrHusbandName ?? ''}', + '${connection.additionalDetails?.collectionPendingAmount != null ? double.parse(connection.additionalDetails?.collectionPendingAmount ?? '') < 0.0 ? '- ₹ ${double.parse(connection.additionalDetails?.collectionPendingAmount ?? '').abs()}' : ' ₹ ${connection.additionalDetails?.collectionPendingAmount}' : '-'}' + ]) + .toList() ?? + []; + + isExcelDownload + ? generateExcel( + headerList + .map((e) => + '${ApplicationLocalizations.of(navigatorKey.currentContext!).translate(e)}') + .toList(), + tableData) + : await HouseholdPdfCreator( + context, + headerList + .map((e) => + '${ApplicationLocalizations.of(navigatorKey.currentContext!).translate(e)}') + .toList(), + tableData, + isDownload) + .pdfPreview(); + Navigator.pop(context); + } + + bool removeOverLay(_overlayEntry) { + try { + if (_overlayEntry == null) return false; + _overlayEntry?.remove(); + return true; + } catch (e) { + return false; + } + } +} diff --git a/frontend/mgramseva/lib/screeens/common/collect_payment.dart b/frontend/mgramseva/lib/screeens/common/collect_payment.dart new file mode 100644 index 000000000..3d84995fd --- /dev/null +++ b/frontend/mgramseva/lib/screeens/common/collect_payment.dart @@ -0,0 +1,629 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_focus_watcher/flutter_focus_watcher.dart'; +import 'package:mgramseva/model/bill/billing.dart'; +import 'package:mgramseva/model/common/fetch_bill.dart' as billDetails; +import 'package:mgramseva/model/common/fetch_bill.dart'; +import 'package:mgramseva/model/demand/demand_list.dart'; +import 'package:mgramseva/model/mdms/payment_type.dart'; +import 'package:mgramseva/providers/collect_payment.dart'; +import 'package:mgramseva/utils/Constants/I18KeyConstants.dart'; +import 'package:mgramseva/utils/Locilization/application_localizations.dart'; +import 'package:mgramseva/utils/common_widgets.dart'; +import 'package:mgramseva/utils/constants.dart'; +import 'package:mgramseva/utils/date_formats.dart'; +import 'package:mgramseva/utils/loaders.dart'; +import 'package:mgramseva/utils/notifyers.dart'; +import 'package:mgramseva/utils/validators/Validators.dart'; +import 'package:mgramseva/widgets/BottonButtonBar.dart'; +import 'package:mgramseva/widgets/ConfirmationPopUp.dart'; +import 'package:mgramseva/widgets/DrawerWrapper.dart'; +import 'package:mgramseva/widgets/FormWrapper.dart'; +import 'package:mgramseva/widgets/HomeBack.dart'; +import 'package:mgramseva/widgets/RadioButtonFieldBuilder.dart'; +import 'package:mgramseva/widgets/SideBar.dart'; +import 'package:mgramseva/widgets/TextFieldBuilder.dart'; +import 'package:provider/provider.dart'; + +import '../../components/HouseConnectionandBill/NewConsumerBill.dart'; +import '../../model/demand/update_demand_list.dart'; +import '../../providers/common_provider.dart'; +import '../../utils/models.dart'; +import '../../widgets/CustomDetails.dart'; +import '../../widgets/customAppbar.dart'; + +class ConnectionPaymentView extends StatefulWidget { + final Map query; + final List? bill; + final List? demandList; + final PaymentType? paymentType; + final List? updateDemandList; + const ConnectionPaymentView( + {Key? key, + required this.query, + this.bill, + this.demandList, + this.paymentType, + this.updateDemandList}) + : super(key: key); + + @override + _ConnectionPaymentViewState createState() => _ConnectionPaymentViewState(); +} + +class _ConnectionPaymentViewState extends State { + final formKey = GlobalKey(); + var autoValidation = false; + + @override + void initState() { + var consumerPaymentProvider = + Provider.of(context, listen: false); + consumerPaymentProvider.getBillDetails(context, widget.query, widget.bill, + widget.demandList, widget.paymentType, widget.updateDemandList); + super.initState(); + } + + static getLabelText(label, value, context, {subLabel = ''}) { + return Container( + padding: EdgeInsets.only(top: 8, bottom: 8, right: 24), + child: (Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only( + right: MediaQuery.of(context).size.width > 760 ? 8 : 36), + padding: EdgeInsets.only(right: 16), + width: MediaQuery.of(context).size.width / 3, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + ApplicationLocalizations.of(context).translate(label), + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w700), + textAlign: TextAlign.start, + ), + subLabel?.trim?.toString() != '' + ? Text( + subLabel, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Theme.of(context).primaryColorLight), + ) + : Text('') + ])), + Text( + value, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400), + textAlign: TextAlign.right, + ) + ], + ))); + } + + @override + Widget build(BuildContext context) { + var consumerPaymentProvider = + Provider.of(context, listen: false); + FetchBill? fetchBill; + return FocusWatcher( + child: Scaffold( + drawer: DrawerWrapper( + Drawer(child: SideBar()), + ), + appBar: CustomAppBar(), + body: StreamBuilder( + stream: consumerPaymentProvider.paymentStreamController.stream, + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + if (snapshot.data is String) { + return CommonWidgets.buildEmptyMessage(snapshot.data, context); + } + fetchBill = snapshot.data; + return _buildView(snapshot.data); + } else if (snapshot.hasError) { + return Notifiers.networkErrorPage( + context, + () => consumerPaymentProvider.getBillDetails( + context, + widget.query, + widget.bill, + widget.demandList, + widget.paymentType, + widget.updateDemandList)); + } else { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Loaders.CircularLoader(); + case ConnectionState.active: + return Loaders.CircularLoader(); + default: + return Container(); + } + } + }), + bottomNavigationBar: Consumer( + builder: (_, consumerPaymentProvider, child) => Visibility( + visible: fetchBill != null, + child: BottomButtonBar( + '${ApplicationLocalizations.of(context).translate(i18.common.COLLECT_PAYMENT)}', + () => showGeneralDialog( + barrierLabel: "Label", + barrierDismissible: false, + barrierColor: Colors.black.withOpacity(0.5), + context: context, + pageBuilder: (context, anim1, anim2) { + return Align( + alignment: Alignment.center, + child: ConfirmationPopUp( + textString: i18.payment.CORE_AMOUNT_CONFIRMATION, + subTextString: + '₹ ${fetchBill?.customAmountCtrl.text}', + cancelLabel: i18.common.CORE_GO_BACK, + confirmLabel: i18.common.CORE_CONFIRM, + onConfirm: () => paymentInfo(fetchBill!, context), + )); + }, + ))), + ), + )); + } + + Widget _buildView(FetchBill fetchBill) { + return SingleChildScrollView( + child: FormWrapper(Form( + key: formKey, + autovalidateMode: autoValidation + ? AutovalidateMode.always + : AutovalidateMode.disabled, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + HomeBack(), + LayoutBuilder( + builder: (_, constraints) => Column( + children: [ + _buildCoonectionDetails(fetchBill, constraints), + _buildPaymentDetails(fetchBill, constraints) + ], + ), + ) + ]), + )), + ); + } + + Widget _buildCoonectionDetails( + FetchBill fetchBill, BoxConstraints constraints) { + return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLabelValue( + i18.common.CONNECTION_ID, '${fetchBill.consumerCode}'), + _buildLabelValue( + i18.common.CONSUMER_NAME, '${fetchBill.payerName}'), + ]))), + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Consumer( + builder: (_, consumerPaymentProvider, child) => Visibility( + visible: fetchBill.viewDetails, + child: _buildViewDetails(fetchBill)), + ), + _buildLabelValue( + i18.common.TOTAL_DUE_AMOUNT, + '₹ ${(fetchBill.totalAmount ?? 0) >= 0 ? fetchBill.totalAmount : 0}', + FontWeight.w700), + Consumer( + builder: (_, consumerPaymentProvider, child) => Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: InkWell( + onTap: () => Provider.of(context, + listen: false) + .onClickOfViewOrHideDetails(fetchBill, context), + child: Text( + fetchBill.viewDetails + ? '${ApplicationLocalizations.of(context).translate(i18.payment.HIDE_DETAILS)}' + : '${ApplicationLocalizations.of(context).translate(i18.payment.VIEW_DETAILS)}', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Theme.of(context).primaryColor), + ), + ), + ), + ) + ]), + ), + ) + ]); + } + + Widget _buildPaymentDetails(FetchBill fetchBill, BoxConstraints constraints) { + return Consumer( + builder: (_, consumerPaymentProvider, child) => Card( + child: Wrap( + children: [ + ForceFocusWatcher( + child: BuildTextField( + i18.common.PAYMENT_AMOUNT, + fetchBill.customAmountCtrl, + textInputType: TextInputType.number, + inputFormatter: [ + FilteringTextInputFormatter.allow(RegExp("[0-9]")) + ], + validator: Validators.partialAmountValidatior, + prefixText: '₹ ', + )), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + '${ApplicationLocalizations.of(context).translate(i18.payment.CORE_CHANGE_THE_AMOUNT)}', + style: TextStyle(color: Colors.blueAccent), + ), + ), + RadioButtonFieldBuilder( + context, + i18.common.PAYMENT_METHOD, + fetchBill.paymentMethod, + '', + '', + true, + consumerPaymentProvider.paymentModeList, + (val) => consumerPaymentProvider.onChangeOfPaymentAmountOrMethod( + fetchBill, val)) + ], + )), + ); + } + + Widget _buildViewDetails(FetchBill fetchBill) { + var penalty = widget.query['status'] != Constants.CONNECTION_STATUS.first + ? CommonProvider.getPenalty(fetchBill.updateDemandList ?? []) + : Penalty(0.0, '0', false); + var isFirstDemand = + CommonProvider.isFirstDemand(fetchBill.demandList ?? []); + List res = []; + num len = fetchBill.billDetails?.first.billAccountDetails?.length as num; + if (fetchBill.billDetails!.isNotEmpty) + fetchBill.billDetails?.forEach((element) { + if (element.amount != 0) res.add(element.amount); + }); + return LayoutBuilder( + builder: (_, constraints) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 10), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + subTitle(i18.payment.BILL_DETAILS), + _buildLabelValue(i18.common.BILL_ID, '${fetchBill.billNumber}'), + _buildLabelValue(i18.payment.BILL_PERIOD, + '${DateFormats.getMonthWithDay(fetchBill.billDetails?.first.fromPeriod)} - ${DateFormats.getMonthWithDay(fetchBill.billDetails?.first.toPeriod)}'), + ]), + ), + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + !isFirstDemand + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (CommonProvider.getPenaltyOrAdvanceStatus( + fetchBill.mdmsData, false) && + !isFirstDemand && + fetchBill.demandList?.first.demandDetails?.first + .taxHeadMasterCode != + '10201' && + fetchBill.demands?.demandDetails?.any((e) => + e.taxHeadMasterCode == '10201') == + true) + _buildLabelValue(i18.billDetails.WS_10201, + '₹ ${CommonProvider.getNormalPenalty(fetchBill.demandList ?? [])}'), + _buildLabelValue( + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY' + ? i18.billDetails.WS_10102 + : 'WS_${fetchBill.demands?.demandDetails?.first.taxHeadMasterCode}', + fetchBill.demandList?.first.demandDetails?.first + .taxHeadMasterCode == + '10201' + ? '₹ ${CommonProvider.getNormalPenalty(fetchBill.demandList ?? [])}' + : '₹ ${CommonProvider.getArrearsAmount(fetchBill.demandList ?? [])}'), + if (!isFirstDemand && + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY') + _buildLabelValue(i18.billDetails.WS_10201, + '₹ ${CommonProvider.getPenaltyApplicable(fetchBill.demandList ?? []).penaltyApplicable}'), + if (fetchBill.demandList?.first.demandDetails?.first + .taxHeadMasterCode == + '10201' && + fetchBill.demandList?.first.demandDetails?.last + .taxHeadMasterCode == + '10102') + _buildLabelValue( + 'WS_${fetchBill.demands?.demandDetails?.last.taxHeadMasterCode}', + '₹ ${((fetchBill.demands?.demandDetails?.last.taxAmount ?? 0) - (fetchBill.demands?.demandDetails?.last.collectionAmount ?? 0)).toString()}') + ]) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLabelValue( + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY' + ? i18.billDetails.CURRENT_BILL + : 'WS_${fetchBill.demands?.demandDetails?.first.taxHeadMasterCode}', + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY' + ? '₹' + + CommonProvider.getCurrentBill( + fetchBill.demandList ?? []) + .toString() + : CommonProvider.checkAdvance( + fetchBill.demandList ?? []) + ? '₹ ${((fetchBill.demands?.demandDetails?.first.taxAmount ?? 0))}' + : '₹ ${((fetchBill.demands?.demandDetails?.first.taxAmount ?? 0) - (fetchBill.demands?.demandDetails?.first.collectionAmount ?? 0))}'), + (fetchBill.billDetails?.first.billAccountDetails + ?.last.arrearsAmount ?? + 0) > + 0 + ? _buildLabelValue( + i18.billDetails.ARRERS_DUES, + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY' + ? '₹' + + CommonProvider + .getArrearsAmountOncePenaltyExpires( + fetchBill.demandList ?? + []) + .toString() + : '₹ ${fetchBill.billDetails?.first.billAccountDetails?.last.arrearsAmount.toString()}') + : SizedBox( + height: 0, + ) + ]), + // }), + if (fetchBill.billDetails != null && res.length > 1) + _buildWaterCharges(fetchBill, constraints), + _buildLabelValue( + i18.common.CORE_TOTAL_BILL_AMOUNT, + isFirstDemand && + fetchBill.demands?.demandDetails?.first + .taxHeadMasterCode == + 'WS_TIME_PENALTY' + ? '₹' + + (CommonProvider.getCurrentBill( + fetchBill.demandList ?? []) + + CommonProvider + .getArrearsAmountOncePenaltyExpires( + fetchBill.demandList ?? [])) + .toString() + : '₹ ${fetchBill.billDetails?.first.billAccountDetails?.last.totalBillAmount}'), + if (CommonProvider.getPenaltyOrAdvanceStatus( + fetchBill.mdmsData, true)) + _buildLabelValue( + i18.common.CORE_ADVANCE_ADJUSTED, + (fetchBill.billDetails?.first.billAccountDetails?.last + .advanceAdjustedAmount != + 0.0 + ? '- ₹ ' + + '${(fetchBill.billDetails?.first.billAccountDetails?.last.advanceAdjustedAmount)}' + : '- ₹ ' + + '${(fetchBill.billDetails?.first.billAccountDetails?.last.advanceAdjustedAmount)}')), + if (CommonProvider.getPenaltyOrAdvanceStatus( + fetchBill.mdmsData, false, true) && + isFirstDemand && + penalty.isDueDateCrossed) + _buildLabelValue( + i18.billDetails.CORE_PENALTY, + '₹' + + (CommonProvider.getPenaltyApplicable( + fetchBill.demandList) + .penaltyApplicable) + .toString()), + if (CommonProvider.getPenaltyOrAdvanceStatus( + fetchBill.mdmsData, true)) + _buildLabelValue(i18.common.CORE_NET_AMOUNT_DUE, + '₹ ${CommonProvider.getNetDueAmountWithWithOutPenalty(fetchBill.totalAmount ?? 0, penalty)}'), + if (CommonProvider.getPenaltyOrAdvanceStatus( + fetchBill.mdmsData, false, true) && + isFirstDemand) + CustomDetailsCard(Column( + children: [ + getLabelText( + i18.billDetails.CORE_PENALTY, + ('₹' + + (penalty.isDueDateCrossed + ? CommonProvider.getPenaltyApplicable( + fetchBill.demandList) + .penaltyApplicable + : penalty.penalty) + .toString()), + context, + subLabel: NewConsumerBillState.getDueDatePenalty( + penalty.date, context)), + getLabelText( + i18.billDetails.CORE_NET_DUE_AMOUNT_WITH_PENALTY, + ('₹' + + (CommonProvider.getNetDueAmountWithWithOutPenalty( + fetchBill.totalAmount ?? 0, + penalty, + true) + .toString()) + .toString()), + context, + subLabel: NewConsumerBillState.getDueDatePenalty( + penalty.date, context)) + ], + )) + ], + ), + ) + ], + ), + ); + } + + Widget _buildWaterCharges(FetchBill bill, BoxConstraints constraints) { + var style = TextStyle( + fontSize: 14, + color: Color.fromRGBO(80, 90, 95, 1), + fontWeight: FontWeight.w400); + + return Container( + padding: EdgeInsets.symmetric( + vertical: 8, horizontal: constraints.maxWidth > 760 ? 20 : 0), + margin: EdgeInsets.symmetric(vertical: 5), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(4)), + child: constraints.maxWidth > 760 + ? Column( + children: List.generate(bill.billDetails?.length ?? 0, (index) { + if (bill.billDetails?[index].billAccountDetails?.first + .taxHeadCode == + 'WS_ADVANCE_CARRYFORWARD') return Container(); + if (index != 0) { + return Row( + children: [ + Container( + width: MediaQuery.of(context).size.width / 3, + padding: EdgeInsets.only(top: 18, bottom: 3), + child: new Align( + alignment: Alignment.centerLeft, + child: _buildDemandDetails( + bill, bill.billDetails![index]))), + Container( + width: MediaQuery.of(context).size.width / 2.5, + padding: EdgeInsets.only(top: 18, bottom: 3), + child: Text('₹ ${bill.billDetails![index].amount}')), + ], + ); + } else { + return SizedBox( + height: 0, + ); + } + })) + : Table( + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: List.generate(bill.billDetails?.length ?? 0, (index) { + if (index == 0 || + bill.billDetails?[index].billAccountDetails?.first + .taxHeadCode == + 'WS_ADVANCE_CARRYFORWARD') { + return TableRow(children: [ + TableCell(child: Text("")), + TableCell(child: Text("")) + ]); + } else { + return TableRow(children: [ + TableCell( + child: _buildDemandDetails( + bill, bill.billDetails![index])), + TableCell( + child: Text( + '₹ ${bill.billDetails![index].amount}', + textAlign: TextAlign.start, + )) + ]); + } + }).toList())); + } + + Widget _buildDemandDetails( + FetchBill bill, billDetails.BillDetails? billdemandDetails) { + var style = TextStyle(fontSize: 14, color: Color.fromRGBO(80, 90, 95, 1)); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 3), + child: Wrap( + direction: Axis.vertical, + spacing: 3, + children: [ + Padding( + padding: EdgeInsets.only(right: 8), + child: Text( + '${ApplicationLocalizations.of(context).translate('BL_${billdemandDetails?.billAccountDetails?.first.taxHeadCode}')}', + style: style)), + Padding( + padding: EdgeInsets.only(right: 8), + child: Text( + '${DateFormats.getMonthWithDay(billdemandDetails?.fromPeriod)}-${DateFormats.getMonthWithDay(billdemandDetails?.toPeriod)}', + style: style)), + ], + ), + ); + } + + Widget _buildLabelValue(String label, String value, + [FontWeight? fontWeight]) { + return LayoutBuilder( + builder: (_, constraints) => constraints.maxWidth > 760 + ? Row( + children: [ + Container( + width: MediaQuery.of(context).size.width / 3, + padding: EdgeInsets.only(top: 18, bottom: 3), + child: new Align( + alignment: Alignment.centerLeft, + child: subTitle('$label', 16))), + Container( + width: MediaQuery.of(context).size.width / 2.5, + padding: EdgeInsets.only(top: 18, bottom: 3, left: 24), + child: Text('$value', + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w400))), + ], + ) + : Table( + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: [ + TableRow(children: [ + TableCell( + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(vertical: 10), + child: subTitle('$label', 16))), + TableCell( + child: Text('$value', + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w400))) + ]) + ])); + } + + paymentInfo(FetchBill fetchBill, BuildContext context) { + var consumerPaymentProvider = + Provider.of(context, listen: false); + if (formKey.currentState!.validate()) { + autoValidation = false; + consumerPaymentProvider.updatePaymentInformation(fetchBill, context); + } else { + setState(() { + autoValidation = true; + }); + } + } + + Text subTitle(String label, [double? size]) => + Text('${ApplicationLocalizations.of(context).translate(label)}', + style: TextStyle(fontSize: size ?? 24, fontWeight: FontWeight.w700)); +}