Update: 2026-05-07 22:19:17
This commit is contained in:
@@ -21,6 +21,8 @@ class ScannerController extends GetxController {
|
||||
var processedImagesCount = 0.obs;
|
||||
var totalImagesCount = 0.obs;
|
||||
var isBatchDone = false.obs;
|
||||
var selectedCompanyId = ''.obs;
|
||||
var selectedCompanyName = ''.obs;
|
||||
|
||||
final InvoiceUploadService _uploadService = InvoiceUploadService();
|
||||
final UploadProgressService _progressService =
|
||||
@@ -90,49 +92,28 @@ class ScannerController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadBatch(String fallbackCompanyId) async {
|
||||
Future<void> uploadBatch() async {
|
||||
if (capturedImages.isEmpty) {
|
||||
AppSnackbar.showWarning('تنبيه', 'الرجاء تصوير فاتورة واحدة على الأقل');
|
||||
return;
|
||||
}
|
||||
if (selectedCompanyId.isEmpty) {
|
||||
AppSnackbar.showWarning('تنبيه', 'الرجاء اختيار الشركة أولاً');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isProcessing.value = true;
|
||||
uploadProgress.value = 0.0;
|
||||
|
||||
String companyId = fallbackCompanyId;
|
||||
String companyName = 'شركة غير محددة';
|
||||
|
||||
if (companyId == 'mock_company_id_123' || companyId.isEmpty) {
|
||||
if (companies.isNotEmpty) {
|
||||
companyId = companies[0]['id'];
|
||||
companyName = companies[0]['name'] ?? 'شركتي';
|
||||
} else {
|
||||
final res = await DioClient().client.get('companies');
|
||||
if (res.data['success'] == true &&
|
||||
res.data['data'] != null &&
|
||||
res.data['data'].isNotEmpty) {
|
||||
companyId = res.data['data'][0]['id'];
|
||||
companyName = res.data['data'][0]['name'] ?? 'شركتي';
|
||||
} else {
|
||||
AppSnackbar.showError('خطأ', 'لا توجد شركات مسجلة في حسابك');
|
||||
isProcessing.value = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final comp = companies.firstWhereOrNull((c) => c['id'] == companyId);
|
||||
if (comp != null) companyName = comp['name'] ?? 'شركتي';
|
||||
}
|
||||
|
||||
AppLogger.print(
|
||||
'Uploading batch of ${capturedImages.length} images to company $companyId...');
|
||||
'Uploading batch of ${capturedImages.length} images to company ${selectedCompanyId.value}...');
|
||||
|
||||
// Start global progress
|
||||
_progressService.startUpload(companyName, capturedImages.length);
|
||||
_progressService.startUpload(selectedCompanyName.value, capturedImages.length);
|
||||
|
||||
final batchId = await _uploadService.uploadBatch(
|
||||
companyId: companyId,
|
||||
companyId: selectedCompanyId.value,
|
||||
images: capturedImages,
|
||||
onProgress: (current, total) {
|
||||
uploadProgress.value = current / total;
|
||||
@@ -149,6 +130,8 @@ class ScannerController extends GetxController {
|
||||
capturedImages.clear();
|
||||
uploadProgress.value = 0.0;
|
||||
isProcessing.value = false;
|
||||
selectedCompanyId.value = '';
|
||||
selectedCompanyName.value = '';
|
||||
|
||||
_progressService.startProcessing();
|
||||
Get.back(); // Go back to dashboard, progress will show in overlay
|
||||
@@ -167,6 +150,11 @@ class ScannerController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
void selectCompany(String id, String name) {
|
||||
selectedCompanyId.value = id;
|
||||
selectedCompanyName.value = name;
|
||||
}
|
||||
|
||||
Future<String> getSavePath() async {
|
||||
final directory = await getTemporaryDirectory();
|
||||
final fileName = 'invoice_${DateTime.now().millisecondsSinceEpoch}.jpg';
|
||||
|
||||
@@ -9,6 +9,72 @@ class ScannerView extends GetView<ScannerController> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() {
|
||||
if (controller.selectedCompanyId.value.isEmpty) {
|
||||
return _buildCompanySelection(context);
|
||||
}
|
||||
return _buildScanner(context);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildCompanySelection(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('اختر الشركة أولاً',
|
||||
style: TextStyle(fontFamily: 'El Messiri')),
|
||||
centerTitle: true,
|
||||
backgroundColor: const Color(0xFF0F4C81),
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
body: Obx(() {
|
||||
if (controller.isLoadingCompanies.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (controller.companies.isEmpty) {
|
||||
return const Center(
|
||||
child: Text('لا توجد شركات مسجلة في حسابك.\nيرجى إضافة شركة أولاً.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 16)),
|
||||
);
|
||||
}
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.all(16),
|
||||
itemCount: controller.companies.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(height: 12),
|
||||
itemBuilder: (context, index) {
|
||||
final company = controller.companies[index];
|
||||
return Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 8),
|
||||
leading: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF0F4C81).withValues(alpha: 0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(Icons.business, color: Color(0xFF0F4C81)),
|
||||
),
|
||||
title: Text(company['name'] ?? '',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 16)),
|
||||
subtitle: Text('الرقم الضريبي: ${company['tax_identification_number'] ?? 'غير محدد'}'),
|
||||
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onTap: () {
|
||||
controller.selectCompany(company['id'], company['name'] ?? '');
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildScanner(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
@@ -131,27 +197,15 @@ class ScannerView extends GetView<ScannerController> {
|
||||
|
||||
// 3. Upload Button
|
||||
Positioned(
|
||||
top: 20,
|
||||
left: 80,
|
||||
right: 80,
|
||||
top: 40,
|
||||
left: 20,
|
||||
right: 20,
|
||||
child: Obx(() => controller.capturedImages.isEmpty
|
||||
? const SizedBox()
|
||||
: ElevatedButton.icon(
|
||||
onPressed: controller.isProcessing.value
|
||||
? null
|
||||
: () {
|
||||
if (controller.companies.isEmpty) {
|
||||
AppSnackbar.showError(
|
||||
'خطأ', 'لا توجد شركات مسجلة في حسابك');
|
||||
return;
|
||||
}
|
||||
if (controller.companies.length == 1) {
|
||||
controller
|
||||
.uploadBatch(controller.companies[0]['id']);
|
||||
return;
|
||||
}
|
||||
_showCompanySelectionDialog(context);
|
||||
},
|
||||
: () => controller.uploadBatch(),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF0F4C81),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
@@ -170,9 +224,9 @@ class ScannerView extends GetView<ScannerController> {
|
||||
strokeWidth: 2))
|
||||
: const Icon(Icons.cloud_upload, color: Colors.white),
|
||||
label: Text(
|
||||
'رفع ${controller.capturedImages.length} فواتير',
|
||||
'رفع ${controller.capturedImages.length} فواتير لـ ${controller.selectedCompanyName.value}',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
),
|
||||
@@ -183,34 +237,5 @@ class ScannerView extends GetView<ScannerController> {
|
||||
);
|
||||
}
|
||||
|
||||
void _showCompanySelectionDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('اختر الشركة',
|
||||
textAlign: TextAlign.right,
|
||||
style: TextStyle(fontFamily: 'El Messiri')),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: controller.companies.length,
|
||||
itemBuilder: (context, index) {
|
||||
final company = controller.companies[index];
|
||||
return ListTile(
|
||||
title: Text(company['name'] ?? '', textAlign: TextAlign.right),
|
||||
subtitle: Text(company['tax_identification_number'] ?? '',
|
||||
textAlign: TextAlign.right),
|
||||
leading: const Icon(Icons.business, color: Color(0xFF0F4C81)),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
controller.uploadBatch(company['id']);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user