first commit
This commit is contained in:
332
lib/Screens/Purchase/bulk purchase/bulk_purchase.dart
Normal file
332
lib/Screens/Purchase/bulk purchase/bulk_purchase.dart
Normal file
@@ -0,0 +1,332 @@
|
||||
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<BulkPurchaseUploader> createState() => _BulkPurchaseUploaderState();
|
||||
}
|
||||
|
||||
class _BulkPurchaseUploaderState extends ConsumerState<BulkPurchaseUploader> {
|
||||
String? filePat;
|
||||
File? file;
|
||||
|
||||
String getFileExtension(String fileName) {
|
||||
return fileName.split('/').last;
|
||||
}
|
||||
|
||||
Future<void> createExcelFile() async {
|
||||
if (!await Permission.storage.request().isDenied) {
|
||||
EasyLoading.showError('Storage permission is required to create Excel file!');
|
||||
return;
|
||||
}
|
||||
EasyLoading.show();
|
||||
final List<e.CellValue> 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<void> 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<void> 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<CartProductModelPurchase?> createProductModelFromExcelData({required List<e.Data?> row, required WidgetRef ref}) async {
|
||||
Future<CartProductModelPurchase?> 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user