190 lines
6.7 KiB
Dart
190 lines
6.7 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:sefer_admin1/constant/colors.dart';
|
|
import 'package:sefer_admin1/constant/links.dart';
|
|
import 'package:sefer_admin1/views/widgets/my_scafold.dart';
|
|
import 'package:sefer_admin1/views/widgets/my_textField.dart';
|
|
|
|
import '../../constant/box_name.dart';
|
|
import '../../constant/info.dart';
|
|
import '../../controller/functions/encrypt_decrypt.dart';
|
|
import '../../main.dart';
|
|
|
|
class AddInvoicePage extends StatefulWidget {
|
|
const AddInvoicePage({super.key});
|
|
|
|
@override
|
|
State<AddInvoicePage> createState() => _AddInvoicePageState();
|
|
}
|
|
|
|
class _AddInvoicePageState extends State<AddInvoicePage> {
|
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
|
final TextEditingController _itemNameController = TextEditingController();
|
|
final TextEditingController _amountController = TextEditingController();
|
|
File? _imageFile;
|
|
bool _isLoading = false;
|
|
|
|
String generateInvoiceNumber() {
|
|
final now = DateTime.now();
|
|
return "INV-${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}-${now.microsecond}";
|
|
}
|
|
|
|
Future<void> uploadInvoice() async {
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
final driverID = '123'; // ← عدّله حسب نظامك
|
|
final invoiceNumber = generateInvoiceNumber();
|
|
final amount = _amountController.text.trim();
|
|
final itemName = _itemNameController.text.trim();
|
|
final date = DateTime.now().toIso8601String().split('T').first;
|
|
|
|
setState(() => _isLoading = true);
|
|
|
|
try {
|
|
final headers = {
|
|
'Authorization':
|
|
'Bearer ${r(box.read(BoxName.jwt)).split(AppInformation.addd)[0]}',
|
|
'X-HMAC-Auth': '${box.read(BoxName.hmac)}',
|
|
};
|
|
final uri = Uri.parse(AppLink.addInvoice);
|
|
final request = http.MultipartRequest('POST', uri)
|
|
..fields['driverID'] = driverID
|
|
..fields['invoiceNumber'] = invoiceNumber
|
|
..fields['amount'] = amount
|
|
..fields['name'] = itemName
|
|
..fields['date'] = date
|
|
..headers.addAll(headers);
|
|
|
|
if (_imageFile != null) {
|
|
final imageName = _imageFile!.path.split('/').last;
|
|
final imageStream = http.ByteStream(_imageFile!.openRead());
|
|
final imageLength = await _imageFile!.length();
|
|
|
|
request.files.add(http.MultipartFile(
|
|
'image',
|
|
imageStream,
|
|
imageLength,
|
|
filename: imageName,
|
|
));
|
|
} else {}
|
|
|
|
final response = await request.send();
|
|
final respStr = await response.stream.bytesToString();
|
|
|
|
final data = jsonDecode(respStr);
|
|
|
|
if (data['status'] == 'success') {
|
|
Get.snackbar('تم الحفظ', 'تم حفظ الفاتورة بنجاح',
|
|
backgroundColor: Colors.green.shade100);
|
|
|
|
_itemNameController.clear();
|
|
_amountController.clear();
|
|
setState(() => _imageFile = null);
|
|
Get.back(); // العودة للصفحة السابقة
|
|
} else {
|
|
Get.snackbar('خطأ', data['message'],
|
|
backgroundColor: Colors.red.shade100);
|
|
}
|
|
} catch (e, stacktrace) {
|
|
Get.snackbar('فشل الإرسال', e.toString(),
|
|
backgroundColor: Colors.red.shade100);
|
|
} finally {
|
|
setState(() => _isLoading = false);
|
|
}
|
|
}
|
|
|
|
Future<void> pickInvoiceImage() async {
|
|
final picker = ImagePicker();
|
|
final picked = await picker.pickImage(source: ImageSource.gallery);
|
|
if (picked != null) {
|
|
setState(() => _imageFile = File(picked.path));
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_itemNameController.dispose();
|
|
_amountController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MyScafolld(
|
|
title: 'إضافة فاتورة جديدة',
|
|
body: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Form(
|
|
key: _formKey,
|
|
child: ListView(
|
|
children: [
|
|
MyTextForm(
|
|
controller: _itemNameController,
|
|
label: 'اسم البضاعة',
|
|
hint: 'مثال: قطع غيار',
|
|
type: TextInputType.text,
|
|
// validator: (val) =>
|
|
// val!.isEmpty ? 'الرجاء إدخال اسم البضاعة' : null,
|
|
),
|
|
const SizedBox(height: 16),
|
|
MyTextForm(
|
|
controller: _amountController,
|
|
label: 'قيمة الفاتورة',
|
|
hint: 'مثال: 150.75',
|
|
type: TextInputType.numberWithOptions(decimal: true),
|
|
// validator: (val) =>
|
|
// val!.isEmpty ? 'الرجاء إدخال المبلغ' : null,
|
|
),
|
|
const SizedBox(height: 20),
|
|
Text('صورة الفاتورة (اختياري)',
|
|
style: Theme.of(context).textTheme.titleMedium),
|
|
const SizedBox(height: 10),
|
|
Container(
|
|
height: 180,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade200,
|
|
border: Border.all(color: Colors.grey.shade400),
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
child: _imageFile != null
|
|
? ClipRRect(
|
|
borderRadius: BorderRadius.circular(10),
|
|
child: Image.file(_imageFile!, fit: BoxFit.cover),
|
|
)
|
|
: const Center(child: Text('لم يتم اختيار صورة')),
|
|
),
|
|
const SizedBox(height: 12),
|
|
ElevatedButton.icon(
|
|
onPressed: pickInvoiceImage,
|
|
icon: const Icon(Icons.image),
|
|
label: const Text('اختيار صورة'),
|
|
),
|
|
const SizedBox(height: 30),
|
|
ElevatedButton(
|
|
onPressed: _isLoading ? null : uploadInvoice,
|
|
style: ElevatedButton.styleFrom(
|
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
backgroundColor: AppColor.primaryColor,
|
|
),
|
|
child: _isLoading
|
|
? const CircularProgressIndicator(color: Colors.white)
|
|
: const Text(
|
|
'حفظ الفاتورة',
|
|
style: TextStyle(color: Colors.white),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
isleading: true,
|
|
);
|
|
}
|
|
}
|