first commit
This commit is contained in:
187
lib/views/invoice/add_invoice_page.dart
Normal file
187
lib/views/invoice/add_invoice_page.dart
Normal file
@@ -0,0 +1,187 @@
|
||||
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 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['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,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user