import 'dart:io'; import 'package:excel/excel.dart' as e; import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mobile_pos/Provider/product_provider.dart'; import 'package:mobile_pos/Screens/Products/add%20product/add_product.dart'; import 'package:mobile_pos/constant.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../../GlobalComponents/glonal_popup.dart'; import '../../../Provider/add_to_cart_purchase.dart'; import '../../../http_client/custome_http_client.dart'; import '../../../service/check_user_role_permission_provider.dart'; import '../../Products/add product/modle/create_product_model.dart'; import '../Repo/purchase_repo.dart'; class BulkPurchaseUploader extends ConsumerStatefulWidget { const BulkPurchaseUploader({super.key}); @override ConsumerState createState() => _BulkPurchaseUploaderState(); } class _BulkPurchaseUploaderState extends ConsumerState { String? filePat; File? file; String getFileExtension(String fileName) { return fileName.split('/').last; } Future createExcelFile() async { if (!await Permission.storage.request().isDenied) { EasyLoading.showError('Storage permission is required to create Excel file!'); return; } EasyLoading.show(); final List excelData = [ e.TextCellValue('SL'), e.TextCellValue('Product Code*'), e.TextCellValue('Purchase Quantity*'), e.TextCellValue('Purchase Price'), e.TextCellValue('Profit Percent %'), e.TextCellValue('Sale Price'), e.TextCellValue('Wholesale Price'), e.TextCellValue('Dealer Price'), e.TextCellValue('Batch No'), e.TextCellValue('Mfg Date'), e.TextCellValue('Expire Date'), ]; e.CellStyle cellStyle = e.CellStyle( bold: true, textWrapping: e.TextWrapping.WrapText, rotation: 0, ); var excel = e.Excel.createExcel(); var sheet = excel['Sheet1']; sheet.appendRow(excelData); for (int i = 0; i < excelData.length; i++) { var cell = sheet.cell(e.CellIndex.indexByColumnRow(columnIndex: i, rowIndex: 0)); cell.cellStyle = cellStyle; } const downloadsFolderPath = '/storage/emulated/0/Download/'; Directory dir = Directory(downloadsFolderPath); final file = File('${dir.path}/${appsName}_bulk_purchase_upload.xlsx'); if (await file.exists()) { EasyLoading.showSuccess('The Excel file has already been downloaded'); } else { await file.writeAsBytes(excel.encode()!); EasyLoading.showSuccess('Downloaded successfully in download folder'); } } @override Widget build(BuildContext context) { final permissionService = PermissionService(ref); return GlobalPopup( child: Scaffold( backgroundColor: kWhite, appBar: AppBar( title: const Text('Excel Uploader'), ), body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Visibility( visible: file != null, child: Padding( padding: const EdgeInsets.only(bottom: 20), child: Card( child: ListTile( leading: Container( height: 40, width: 40, padding: const EdgeInsets.all(2), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: const BorderRadius.all(Radius.circular(10)), ), child: const Image(image: AssetImage('images/excel.png'))), title: Text( getFileExtension(file?.path ?? ''), maxLines: 2, overflow: TextOverflow.ellipsis, ), trailing: GestureDetector( onTap: () { setState(() { file = null; }); }, child: const Text('Remove')))), ), ), Visibility( visible: file == null, child: const Padding( padding: EdgeInsets.only(bottom: 20), child: Image( height: 100, width: 100, image: AssetImage('images/file-upload.png'), )), ), ElevatedButton( style: const ButtonStyle(backgroundColor: WidgetStatePropertyAll(kMainColor)), onPressed: () async { if (!permissionService.hasPermission(Permit.bulkUploadsCreate.value)) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.red, content: Text('You do not have permission to upload bulk.'), ), ); return; } if (file == null) { await pickAndUploadFile(ref: ref); } else { EasyLoading.show(status: 'Uploading...'); await uploadProducts(ref: ref, file: file!, context: context); EasyLoading.dismiss(); } }, child: Text(file == null ? 'Pick and Upload File' : 'Upload', style: const TextStyle(color: Colors.white)), ), TextButton( onPressed: () async { if (!permissionService.hasPermission(Permit.bulkUploadsRead.value)) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: Colors.red, content: Text('You do not have permission to download file.'), ), ); return; } await createExcelFile(); }, child: const Text('Download Excel Format'), ), ], ), ), ), ), ); } /// Future pickAndUploadFile({required WidgetRef ref}) async { const XTypeGroup typeGroup = XTypeGroup( label: 'Excel Files', extensions: ['xlsx'], ); final XFile? fileResult = await openFile(acceptedTypeGroups: [typeGroup]); if (fileResult != null) { final File files = File(fileResult.path); setState(() { file = files; }); } else { print("No file selected"); } } Future uploadProducts({ required File file, required WidgetRef ref, required BuildContext context, }) async { try { final purchaseCart = ref.watch(cartNotifierPurchaseNew); e.Excel excel = e.Excel.decodeBytes(file.readAsBytesSync()); var sheet = excel.sheets.keys.first; var table = excel.tables[sheet]!; for (var row in table.rows) { CartProductModelPurchase? data = await createProductModelFromExcelData(row: row, ref: ref); if (data != null) purchaseCart.addToCartRiverPod(cartItem: data, isVariation: data.productType == ProductType.variant.name); } Future.delayed(const Duration(seconds: 1), () { EasyLoading.showSuccess('Upload Done'); int count = 0; Navigator.popUntil(context, (route) { return count++ == 1; }); }); } catch (e) { EasyLoading.showError(e.toString()); return; } } Future createProductModelFromExcelData({required List row, required WidgetRef ref}) async { Future getProductFromDatabase({required WidgetRef ref, required String givenProductCode}) async { final products = ref.watch(productProvider); CartProductModelPurchase? cartProductModel; // Wait for the category data to load await products.when( data: (product) async { for (var element in product) { if (element.productCode?.toLowerCase().trim() == givenProductCode.toLowerCase().trim()) { cartProductModel = CartProductModelPurchase( productId: element.id ?? 0, vatRate: element.vat?.rate ?? 0, productName: element.productName ?? '', vatAmount: element.vatAmount ?? 0, vatType: element.vatType ?? '', productWholeSalePrice: 0, productDealerPrice: 0, productPurchasePrice: 0, productSalePrice: 0, productType: element.productType ?? 'single', quantities: 0, stock: 0, brandName: '', profitPercent: 0, mfgDate: '', expireDate: '', batchNumber: '', ); return cartProductModel; } } }, error: (error, stackTrace) {}, loading: () {}, ); return cartProductModel; } CartProductModelPurchase? productModel; // Loop through the row data for (var element in row) { if (element?.rowIndex == 0) { // Skip header row return null; } switch (element?.columnIndex) { case 1: // Product code if (element?.value == null) return null; productModel = await getProductFromDatabase(ref: ref, givenProductCode: element?.value.toString() ?? ''); break; case 2: // Product quantity if (element?.value == null) return null; productModel?.quantities = num.tryParse(element?.value.toString() ?? '0'); break; case 3: // purchase price productModel?.productPurchasePrice = num.tryParse(element?.value.toString() ?? '') ?? 0; break; case 4: // profit percent productModel?.profitPercent = num.tryParse(element?.value.toString() ?? '') ?? 0; break; case 5: // sales price productModel?.productSalePrice = num.tryParse(element?.value.toString() ?? '') ?? 0; break; case 6: // wholesale price productModel?.productWholeSalePrice = num.tryParse(element?.value.toString() ?? '') ?? 0; break; case 7: //dealer price if (element?.value != null) { productModel?.productDealerPrice = num.tryParse(element?.value.toString() ?? '') ?? 0; } break; case 8: // Batch (optional) if (element?.value != null) { productModel?.batchNumber = element?.value.toString() ?? ''; } break; case 9: // mgf date (optional) if (element?.value != null) { productModel?.mfgDate = element?.value.toString() ?? ''; } break; case 10: // expire date (optional) if (element?.value != null) { productModel?.expireDate = element?.value.toString() ?? ''; } break; } } // Return null if any of the required fields are missing if (productModel?.productName == null || productModel?.quantities == null) { return null; } return productModel; } }