import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'dart:io'; import 'package:csv/csv.dart'; import 'package:excel/excel.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:generp/Notifiers/HomeScreenNotifier.dart'; import 'package:generp/Utils/app_colors.dart'; import 'package:generp/services/api_calling.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:path_provider/path_provider.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:permission_handler/permission_handler.dart'; import 'package:printing/printing.dart'; import 'package:provider/provider.dart'; import '../../Models/financeModels/addReceiptPaymentResponse.dart'; import '../../Models/financeModels/paymentRequisitionPaymentsReceiptsDetailsResponse.dart'; import '../../Models/financeModels/paymentRequisitionPaymentsReceiptsListResponse.dart'; import '../../Utils/commonServices.dart'; import 'package:share_plus/share_plus.dart'; import 'package:printing/printing.dart'; class Paymentreceiptsprovider extends ChangeNotifier { bool _showMoreDetails = false; List _receiptsList = []; ReceiptDetails _receiptDetails = ReceiptDetails(); List _headings = []; List _subHeadings = []; List get receiptsList => _receiptsList; ReceiptDetails get receiptDetails => _receiptDetails; List get Headings => _headings; List get subHeadings => _subHeadings; TextEditingController reqPurposeController = TextEditingController(); TextEditingController descController = TextEditingController(); TextEditingController amountController = TextEditingController(); TextEditingController bankNameController = TextEditingController(); TextEditingController bankBranchController = TextEditingController(); TextEditingController bankAccNumberController = TextEditingController(); TextEditingController bankIfscController = TextEditingController(); TextEditingController bankAcHolderController = TextEditingController(); TextEditingController bankUpiController = TextEditingController(); TextEditingController paymentReferenceController = TextEditingController(); TextEditingController dateController = TextEditingController(); TextEditingController accountSearchController = TextEditingController(); TextEditingController paymentAccountSearchController = TextEditingController(); // Date picker state DateTime? _date; String? _formattedDate; String? _formattedDateToSend; List _accounts = []; List _paymentModes = []; List _requestingPurposes = []; List _receiptAccounts = []; List _receiptPaymentAccounts = []; List _receiptPaymentModes = []; Accounts? _selectedreceiptAccounts; ReceiptAccounts? _selectreceiptPaymentAccounts; PaymentModes? _selectreceiptPaymentModes; String _receiptAccountID = ""; String _receiptAccountValue = ""; String _receiptPaymentAccountsID = ""; String _receiptPaymentAccountsValue = ""; String _receiptPaymentModesID = ""; String _receiptPaymentModesValues = ""; bool get showMoreDetails => _showMoreDetails; List get receiptAccounts => _receiptAccounts; List get receiptPaymentAccounts => _receiptPaymentAccounts; List get receiptPaymentModes => _receiptPaymentModes; Accounts? get selectreceiptAccounts => _selectedreceiptAccounts; ReceiptAccounts? get selectreceiptPaymentAccounts => _selectreceiptPaymentAccounts; PaymentModes? get selectreceiptPaymentModes => _selectreceiptPaymentModes; String get receiptAccountId => _receiptAccountID; String get receiptAccountValue => _receiptAccountValue; String get receiptPaymentAccountsID => _receiptPaymentAccountsID; String get receiptPaymentAccountsValue => _receiptPaymentAccountsValue; String get receiptPaymentModesID => _receiptPaymentModesID; String get receiptPaymentModesValues => _receiptPaymentModesValues; // Date picker methods set showMoreDetails(bool value){ _showMoreDetails = value; notifyListeners(); } set selectreceiptAccounts(Accounts? value) { _selectedreceiptAccounts = value; _receiptAccountID = value!.id!; _receiptAccountValue = value!.name!; selectAccountError = null; notifyListeners(); } set selectreceiptPaymentAccounts(ReceiptAccounts? value) { _selectreceiptPaymentAccounts = value; _receiptPaymentAccountsID = value!.id!; _receiptPaymentAccountsValue = value!.name!; selectPaymentAccountError = null; notifyListeners(); } set selectreceiptPaymentModes(PaymentModes? value) { _selectreceiptPaymentModes = value; _receiptPaymentModesID = value!.id!; _receiptPaymentModesValues = value!.name!; paymentModeError = null; notifyListeners(); } set receiptAccountId(String value) { _receiptAccountID = value; notifyListeners(); } set receiptAccountValue(String value) { _receiptAccountValue = value; notifyListeners(); } set receiptPaymentAccountsID(String value) { _receiptPaymentAccountsID = value; notifyListeners(); } set receiptPaymentAccountsValue(String value) { _receiptPaymentAccountsValue = value; notifyListeners(); } set receiptPaymentModesID(String value) { _receiptPaymentModesID = value; paymentModeError = null; notifyListeners(); } set receiptPaymentModesValues(String value) { _receiptPaymentModesValues = value; notifyListeners(); } Accounts? _selectedAccounts; PaymentModes? _selectedPayment; String? _selectReqPurpose; String _paymentModeId = ""; String _paymentModeValue = ""; String _accountId = ""; String _reqPurpose = ""; String? selectAccountError; String? selectPaymentAccountError; String? reqPurposeError; String? paymentModeError; String? paymentreferenceError; String? descriptionError; String? amountError; String? selectPaymentError; String? bankNameError; String? bankBranchError; String? bankNumberError; String? bankIFSCError; String? bankHolderError; String? UPIError; String? FileError; String? dateError; bool buttonEnabled = false; bool _isLoading = true; bool _submitClicked = false; var _image_picked = 0; final ImagePicker _picker = ImagePicker(); File? _image; File? _imageName; bool get isLoading => _isLoading; String get paymentModeId => _paymentModeId; String get paymentModeValue => _paymentModeValue; get image_picked => _image_picked; File? get imagePath => _imageName; File? get imageFilePath => _image; get imagePicked => _image_picked; String get accountId => _accountId; String get reqPurpose => _reqPurpose; String? get selectReqPurpose => _selectReqPurpose; Accounts? get selectedAccount => _selectedAccounts; PaymentModes? get selectedPayment => _selectedPayment; List get accounts => _accounts; List get paymentModes => _paymentModes; List get requestingPurposes => _requestingPurposes; String? get formattedDate => _formattedDate; String? get formattedDateToSend => _formattedDateToSend; bool get submitClicked => _submitClicked; set submitClicked(bool value) { _submitClicked = value; notifyListeners(); } set imagePath(File? value) { _imageName = value; notifyListeners(); } set imageFilePath(File? value) { _image = value; notifyListeners(); } set imagePicked(value) { _image_picked = value; notifyListeners(); } set formattedDate(String? value) { _formattedDate = value; dateController.text = _formattedDate!; dateError = null; notifyListeners(); } void setDate(DateTime newDate) { _date = newDate; _formattedDate = DateFormat('d MMM yyyy').format(newDate); _formattedDateToSend = DateFormat('yyyy-MM-dd').format(newDate); dateController.text = _formattedDate!; dateError = null; notifyListeners(); } set selectedAccount(Accounts? value) { _selectedAccounts = value; _accountId = value!.id!; selectAccountError = null; notifyListeners(); } set selectedPayment(PaymentModes? value) { _selectedPayment = value; _paymentModeId = value!.id!; _paymentModeValue = value!.name!; selectPaymentError = null; notifyListeners(); } set selectReqPurpose(String? value) { _selectReqPurpose = value; reqPurposeError = null; notifyListeners(); } set paymentModeId(String value) { _paymentModeId = value; notifyListeners(); } set paymentModeValue(String value) { _paymentModeValue = value; notifyListeners(); } set accountId(String value) { _accountId = value; notifyListeners(); } set reqPurposeId(String value) { _reqPurpose = value; notifyListeners(); } imgFromCamera(context) async { // Capture a photo try { final XFile? galleryImage = await _picker.pickImage( source: ImageSource.camera, imageQuality: 50, ); debugPrint("added"); _image = File(galleryImage!.path); _imageName = File(galleryImage!.name); _image_picked = 1; FileError = null; notifyListeners(); } catch (e) { debugPrint("mmmm: ${e.toString()}"); } } imgFromGallery(context) async { // Pick an image try { final XFile? galleryImage = await _picker.pickImage( source: ImageSource.gallery, ); final bytes = (await galleryImage?.readAsBytes())?.lengthInBytes; final kb = bytes! / 1024; final mb = kb / 1024; debugPrint("Jenny: bytes:$bytes, kb:$kb, mb: $mb"); _image = File(galleryImage!.path); _imageName = File(galleryImage!.name); _image_picked = 1; FileError = null; notifyListeners(); // var file = FlutterImageCompress.compressWithFile(galleryImage!.path); } catch (e) { debugPrint("mmmm: ${e.toString()}"); } } Future paymentsListAPI(context, from, to) async { try { var prov = Provider.of(context, listen: false); _isLoading = true; notifyListeners(); final data = await ApiCalling.paymentRequisitionPaymentReceiptListAPI( prov.empId, prov.session, from, to, ); if (data != null) { if (data.error == "0") { _receiptsList = data.receiptsList!; _isLoading = false; notifyListeners(); } else if (data.error == "1") { _isLoading = false; } notifyListeners(); } } catch (e, s) {} } Future paymentsListDetailsAPI(context, paymentId) async { try { var prov = Provider.of(context, listen: false); final data = await ApiCalling.paymentRequisitionPaymentReceiptDetailsAPI( prov.empId, prov.session, paymentId, ); if (data != null) { if (data.error == "0") { _receiptDetails = data.receiptDetails!; _headings = [ "Payment Mode", "Created Employee", "Attachment", "Receipt Date", "Note", "Bank Name", "Bank Branch Name", "Bank IFSC Code", "Bank Holder Name", "Bank Account Number", "Bank UPI ID", "Payment Reference Number", "Created Date Time", "Updated Date Time", ]; _subHeadings = [ _receiptDetails.requestMode ?? "-", _receiptDetails.createdEmployee ?? "-", _receiptDetails.attachmentDirFilePath ?? "-", _receiptDetails.receiptDate ?? "-", _receiptDetails.description ?? "-", _receiptDetails.bankName ?? "-", _receiptDetails.bankBranchName ?? "-", _receiptDetails.bankIfscCode ?? "-", _receiptDetails.bankAccountHolderName ?? "-", _receiptDetails.bankAccountNumber ?? "-", _receiptDetails.bankUpiId ?? "-", _receiptDetails.paymentReferenceNumber ?? "-", _receiptDetails.createdDatetime ?? "-", _receiptDetails.updatedDatetime ?? "-", ]; notifyListeners(); } } } catch (e, s) {} } Future addReceiptPaymentRequestionViewAPI(context) async { try { var homeProvider = Provider.of( context, listen: false, ); final data = await ApiCalling.addReceiptPaymentRequestionViewAPI( homeProvider.empId, homeProvider.session, ); if (data != null) { if (data.error == "0") { _receiptPaymentAccounts = data.receiptAccounts!; _receiptPaymentAccounts = [ ReceiptAccounts(name: "Select", id: ""), ...data.receiptAccounts!, ]; _receiptPaymentModes = data.paymentModes!; _receiptPaymentModes = [ PaymentModes(name: "Select", id: ""), ...data.paymentModes!, ]; _receiptAccounts = data.accounts!; _receiptAccounts = [ Accounts(name: "Select", id: ""), ...data.accounts!, ]; checkDropDownSelected(); notifyListeners(); } else {} } } catch (e, s) {} } Future addReceiptPaymentRequestionSubmitAPI( context, receipt_date, ) async { try { _submitClicked = true; notifyListeners(); if (!validatereceiptForm(context)) { return; } var homeProvider = Provider.of( context, listen: false, ); final data = await ApiCalling.addReceiptPaymentRequestionSubmitAPI( homeProvider.empId, homeProvider.session, _receiptAccountID, _receiptPaymentAccountsID, descController.text, _receiptPaymentModesID, amountController.text, receipt_date, paymentReferenceController.text, bankNameController.text, bankBranchController.text, bankAccNumberController.text, bankIfscController.text, bankAcHolderController.text, bankUpiController.text, _image, ); if (data != null) { if (data.error == "0") { _submitClicked = false; toast(context, "Added Successfully"); resetForm(); notifyListeners(); Navigator.of(context).pop(context); } else { _submitClicked = true; notifyListeners(); } } else { _submitClicked = true; notifyListeners(); } } catch (e, s) { _submitClicked = true; notifyListeners(); } } List> prepareExportData() { final headers = [ 'ID', 'Payment Account', 'Amount', 'Branch', 'Account Number', 'Description', 'Mode', 'Payment Reference Number', 'Created Employee', 'Date', ]; final rows = receiptsList .map( (item) => [ item.id ?? '', item.payAccount ?? '', item.amount ?? '', item.bankName ?? "", item.bankBranchName ?? '', item.bankAccountNumber ?? '', item.description ?? '', item.requestMode ?? '', item.paymentReferenceNumber ?? '', item.createdEmployee ?? '', item.createdDatetime ?? '', ], ) .toList(); return [headers, ...rows]; } void copyToClipboard(BuildContext context) async { try { if (receiptsList.isEmpty) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text("No data to copy"))); return; } final data = prepareExportData(); String raw = data.map((row) => row.join('\t')).join('\n'); print('Clipboard data: $raw'); await Clipboard.setData(ClipboardData(text: raw)); toast(context, "Copied to Clipboard"); } catch (e) { print('Error copying to clipboard: $e'); } } Future getSavereceiptory() async { // Try Downloads receiptory first try { if (Platform.isAndroid) { // Request storage permission for Android if (await Permission.storage.request().isGranted || await Permission.manageExternalStorage.request().isGranted) { final dir = await getApplicationDocumentsDirectory(); if (dir != null) { print('Using Downloads receiptory: ${dir.path}'); return dir.path; } } } } catch (e) { print('Error accessing Downloads receiptory: $e'); } // Fallback to shared Documents receiptory try { final dir = await getDownloadsDirectory(); if (dir != null) { final customDir = Directory('${dir.path}/RequisitionData'); if (!await customDir.exists()) { await customDir.create(recursive: true); } print('Using custom Documents receiptory: ${customDir.path}'); return customDir.path; } } catch (e) { print('Error accessing Documents receiptory: $e'); } // Final fallback to app's Documents receiptory final dir = await getApplicationDocumentsDirectory(); print('Using app Documents receiptory: ${dir.path}'); return dir.path; } Future downloadCSV(BuildContext context) async { try { if (receiptsList.isEmpty) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text("No data to export"))); return; } final data = prepareExportData(); final csvData = const ListToCsvConverter().convert(data); final dirPath = await getSavereceiptory(); final file = File('$dirPath/requisition_data.csv'); await file.writeAsString(csvData); print('CSV saved at: ${file.path}'); bool exists = await file.exists(); print('File exists: $exists'); // await OpenFile.open(file.path); // Open the file // await Share.share(file.path); // Share the file toast(context, "CSV Downloaded"); } catch (e) { print('Error downloading CSV: $e'); } } Future downloadXLS(BuildContext context) async { try { if (receiptsList.isEmpty) { toast(context, "No Data to export"); return; } final data = prepareExportData(); var excel = Excel.createExcel(); Sheet sheet = excel['Sheet1']; for (var row in data) { sheet.appendRow(row.map((cell) => TextCellValue(cell)).toList()); } final dirPath = await getSavereceiptory(); final file = File('$dirPath/requisition_data.xlsx'); final bytes = excel.encode(); if (bytes == null) throw Exception("Excel encoding failed"); await file.writeAsBytes(bytes); print('XLSX saved at: ${file.path}'); bool exists = await file.exists(); print('File exists: $exists'); // await OpenFile.open(file.path); // Open the file // await Share.share([file.path], text: 'Requisition Data XLSX'); // Share the file toast(context, ("XLSX Downloaded and opened")); } catch (e) { print('Error downloading XLSX: $e'); } } Future downloadPDF(BuildContext context) async { try { if (receiptsList.isEmpty) { toast(context, "No Data to export"); return; } final data = prepareExportData(); final pdf = pw.Document(); pdf.addPage( pw.Page(build: (context) => pw.Table.fromTextArray(data: data)), ); final dirPath = await getSavereceiptory(); final file = File('$dirPath/requisition_data.pdf'); await file.writeAsBytes(await pdf.save()); print('PDF saved at: ${file.path}'); bool exists = await file.exists(); print('File exists: $exists'); // await OpenFile.open(file.path); // Open the file // await Share.shareXFiles([file.path], text: 'Requisition Data PDF'); // Share the file toast(context, "PDF Downloaded "); } catch (e) { print('Error downloading PDF: $e'); } } Future printData(BuildContext context) async { try { if (receiptsList.isEmpty) { toast(context, "No Data to Print"); return; } final data = prepareExportData(); final pdf = pw.Document(); pdf.addPage( pw.Page(build: (context) => pw.Table.fromTextArray(data: data)), ); await Printing.layoutPdf( onLayout: (PdfPageFormat format) async => pdf.save(), ); } catch (e) { print('Error printing data: $e'); } } void resetForm() { print("rf"); _submitClicked = false; accountSearchController.clear(); paymentAccountSearchController.clear(); reqPurposeController.clear(); descController.clear(); amountController.clear(); bankNameController.clear(); bankBranchController.clear(); bankAccNumberController.clear(); bankIfscController.clear(); bankAcHolderController.clear(); bankUpiController.clear(); paymentReferenceController.clear(); dateController.clear(); _selectedreceiptAccounts = null; _selectreceiptPaymentAccounts = null; _selectreceiptPaymentModes = null; _selectReqPurpose = null; _formattedDate = ""; _paymentModeId = ""; _paymentModeValue = ""; _accountId = ""; _reqPurpose = ""; _image = null; _imageName = null; _image_picked = 0; // _submitClicked = false; // Clear validation errors selectAccountError = null; selectPaymentAccountError = null; dateError = null; paymentreferenceError = null; paymentModeError = null; reqPurposeError = null; paymentreferenceError = null; descriptionError = null; amountError = null; selectPaymentError = null; bankNameError = null; bankBranchError = null; bankNumberError = null; bankIFSCError = null; bankHolderError = null; UPIError = null; FileError = null; buttonEnabled = false; dateError = null; _formattedDateToSend = null; _formattedDate = null; _date = null; _showMoreDetails = false; checkDropDownSelected(); notifyListeners(); } void checkDropDownSelected() { if (_selectedreceiptAccounts != null && !_receiptAccounts.contains(_selectedreceiptAccounts)) { _selectedreceiptAccounts = null; _receiptAccountID = ""; _receiptAccountValue = ""; } if (_selectreceiptPaymentModes != null && !_receiptPaymentModes.contains(_selectreceiptPaymentModes)) { _selectreceiptPaymentModes = null; _receiptPaymentModesID = ""; _receiptPaymentModesValues = ""; } if (_selectreceiptPaymentAccounts != null && !_receiptPaymentAccounts.contains(_selectreceiptPaymentAccounts)) { _selectreceiptPaymentAccounts = null; _receiptPaymentAccountsID = ""; _receiptPaymentAccountsValue = ""; } } bool validatereceiptForm(BuildContext context) { selectAccountError = null; selectPaymentAccountError = null; reqPurposeError = null; descriptionError = null; amountError = null; selectPaymentError = null; bankNameError = null; bankBranchError = null; bankNumberError = null; bankIFSCError = null; bankHolderError = null; paymentreferenceError = null; UPIError = null; bool isValid = true; if (_selectedreceiptAccounts == null || _receiptAccountID.trim().isEmpty) { selectAccountError = "Please select an Account"; _submitClicked = false; isValid = false; } if (_selectreceiptPaymentAccounts == null || _receiptPaymentAccountsID.isEmpty) { selectPaymentAccountError = "Please select an Account"; _submitClicked = false; isValid = false; } if (amountController.text.trim().isEmpty) { amountError = "Please enter an amount"; _submitClicked = false; isValid = false; } if (dateController.text.trim().isEmpty || _formattedDate!.isEmpty) { dateError = "Please select Date"; isValid = false; _submitClicked = false; } if (_selectreceiptPaymentModes == null || _receiptPaymentModesID.isEmpty) { selectPaymentError = "Please select a payment mode"; isValid = false; _submitClicked = false; } if (["Cheque", "RTGS", "IMPS", "NEFT"].contains(_paymentModeValue)) { if (bankNameController.text.trim().isEmpty) { bankNameError = "Please enter bank name"; isValid = false; _submitClicked = false; } if (bankBranchController.text.trim().isEmpty) { bankBranchError = "Please enter bank branch"; isValid = false; _submitClicked = false; } if (bankAccNumberController.text.trim().isEmpty) { bankNumberError = "Please enter account number"; isValid = false; _submitClicked = false; } if (bankIfscController.text.trim().isEmpty) { bankIFSCError = "Please enter IFSC code"; isValid = false; _submitClicked = false; } if (bankAcHolderController.text.trim().isEmpty) { bankHolderError = "Please enter account holder name"; isValid = false; _submitClicked = false; } } if (_paymentModeValue == "UPI") { if (bankUpiController.text.trim().isEmpty) { UPIError = "Please enter UPI ID"; isValid = false; _submitClicked = false; } } if (paymentReferenceController.text.trim().isEmpty) { paymentreferenceError = "please enter refernce number"; isValid = false; _submitClicked = false; } if (descController.text.trim().isEmpty) { descriptionError = "Please Enter Description"; isValid = false; _submitClicked = false; } _submitClicked = false; notifyListeners(); return isValid; } void updateReqPupose(String value) { reqPurposeError = null; notifyListeners(); } void updatereference(String value) { paymentreferenceError = null; notifyListeners(); } void updateDescription(String value) { descriptionError = null; notifyListeners(); } void updateAmount(String value) { amountError = null; notifyListeners(); } void updateBankName(String value) { bankNameError = null; notifyListeners(); } void updateBankBranch(String value) { bankBranchError = null; notifyListeners(); } void updateNumber(String value) { bankNumberError = null; notifyListeners(); } void updateIFSC(String value) { bankIFSCError = null; notifyListeners(); } void updateHolder(String value) { bankHolderError = null; notifyListeners(); } void updateUPI(String value) { UPIError = null; notifyListeners(); } void showDatePickerDialog(BuildContext context) { showCupertinoModalPopup( context: context, builder: (BuildContext context) => Container( height: 216, padding: const EdgeInsets.only(top: 6.0), margin: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), color: CupertinoColors.systemBackground.resolveFrom(context), child: SafeArea( top: false, child: Column( children: [ Expanded( flex: 2, child: SizedBox( height: 40, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ CupertinoButton( child: Text( 'Cancel', style: TextStyle( fontFamily: "JakartaMedium", color: AppColors.app_blue, ), ), onPressed: () { Navigator.pop(context); }, ), CupertinoButton( child: Text( 'Done', style: TextStyle( fontFamily: "JakartaMedium", color: AppColors.app_blue, ), ), onPressed: () { setDate(_date ?? DateTime.now() ); Navigator.pop(context); }, ), ], ), ), ), Expanded( flex: 4, child: CupertinoDatePicker( dateOrder: DatePickerDateOrder.dmy, initialDateTime: _date ?? DateTime.now(), mode: CupertinoDatePickerMode.date, use24hFormat: true, showDayOfWeek: true, onDateTimeChanged: (DateTime newDate) { setDate(newDate); }, ), ), ], ), ), ), ); } }