Web approach uniformity done

This commit is contained in:
2026-08-30 19:54:54 +05:30
parent 372c2bc14d
commit eb39d5ff90
12 changed files with 2724 additions and 1201 deletions

View File

@@ -130,13 +130,42 @@ class _InvoiceBuilderScreenState extends ConsumerState<InvoiceBuilderScreen> {
}
Future<void> _pickInvoiceFile() async {
final picker = ImagePicker();
final picked = await picker.pickImage(
source: ImageSource.gallery,
imageQuality: 80,
);
if (picked != null) {
setState(() => _invoiceFile = picked);
try {
final picker = ImagePicker();
final picked = await picker.pickImage(
source: ImageSource.gallery,
imageQuality: 80,
);
if (picked != null) {
setState(() {
_invoiceFile = picked;
_isLoading = true;
});
final bytes = await picked.readAsBytes();
final formData = FormData.fromMap({
'file': MultipartFile.fromBytes(
bytes,
filename: picked.name.isNotEmpty ? picked.name : 'invoice_${DateTime.now().millisecondsSinceEpoch}.jpg',
),
'type': 'SALES_INVOICE',
});
final uploadResp = await DioClient().dio.post(
'/upload',
data: formData,
);
if (uploadResp.statusCode == 200) {
setState(() {
_invoiceUrl = uploadResp.data['url'];
});
}
}
} catch (e) {
debugPrint('Error uploading sales invoice attachment: $e');
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
@@ -280,11 +309,12 @@ class _InvoiceBuilderScreenState extends ConsumerState<InvoiceBuilderScreen> {
try {
String? finalInvoiceUrl = _invoiceUrl;
if (_invoiceFile != null) {
if (_invoiceFile != null && finalInvoiceUrl == null) {
final bytes = await _invoiceFile!.readAsBytes();
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
_invoiceFile!.path,
filename: _invoiceFile!.name,
'file': MultipartFile.fromBytes(
bytes,
filename: _invoiceFile!.name.isNotEmpty ? _invoiceFile!.name : 'invoice.jpg',
),
'type': 'SALES_INVOICE',
});
@@ -366,12 +396,15 @@ class _InvoiceBuilderScreenState extends ConsumerState<InvoiceBuilderScreen> {
}
final invoiceDiscount = double.tryParse(_discountCtrl.text) ?? 0.0;
totalDiscount = invoiceDiscount;
grandTotal = (subtotal + totalMaking - invoiceDiscount).clamp(0.0, double.infinity) + totalTax;
totalDiscount = double.parse(invoiceDiscount.toStringAsFixed(2));
final rawGrandTotal = (subtotal + totalMaking - invoiceDiscount).clamp(0.0, double.infinity) + totalTax;
grandTotal = double.parse(rawGrandTotal.toStringAsFixed(2));
final amountPaid = double.tryParse(_amountPaidCtrl.text) ?? (_isAmountPaidEdited ? 0.0 : grandTotal);
final validAmountPaid = amountPaid > grandTotal ? grandTotal : amountPaid;
final balanceDue = grandTotal - validAmountPaid;
final validAmountPaid = double.parse((amountPaid > grandTotal ? grandTotal : amountPaid).toStringAsFixed(2));
final balanceDue = double.parse((grandTotal - validAmountPaid).clamp(0.0, double.infinity).toStringAsFixed(2));
final isFullyPaid = balanceDue.abs() < 0.01 || validAmountPaid >= grandTotal - 0.01;
final determinedStatus = isFullyPaid ? 'PAID' : (validAmountPaid > 0.01 ? 'PARTIAL' : 'DRAFT');
final invoice = Invoice(
id: widget.existingInvoice?.id,
@@ -379,18 +412,20 @@ class _InvoiceBuilderScreenState extends ConsumerState<InvoiceBuilderScreen> {
invoiceNumber: _invoiceNumberCtrl.text.trim(),
issueDate: _invoiceDate,
dueDate: _dueDate,
subtotal: subtotal,
taxTotal: totalTax,
cgstTotal: totalCgst,
sgstTotal: totalSgst,
igstTotal: totalIgst,
subtotal: double.parse(subtotal.toStringAsFixed(2)),
taxTotal: double.parse(totalTax.toStringAsFixed(2)),
cgstTotal: double.parse(totalCgst.toStringAsFixed(2)),
sgstTotal: double.parse(totalSgst.toStringAsFixed(2)),
igstTotal: double.parse(totalIgst.toStringAsFixed(2)),
discountTotal: totalDiscount,
totalAmount: grandTotal,
amountPaid: validAmountPaid,
paymentMethod: validAmountPaid > 0 ? _paymentMethod : null,
paymentWalletId: validAmountPaid > 0 ? (_selectedWalletId ?? ref.read(walletProvider).value?.firstOrNull?.id) : null,
nextPaymentDate: balanceDue > 0 ? (_nextPaymentDate ?? DateTime.now().add(const Duration(days: 30))) : null,
status: widget.existingInvoice?.status ?? (validAmountPaid >= grandTotal ? 'PAID' : (validAmountPaid > 0 ? 'PARTIAL' : 'DRAFT')),
nextPaymentDate: balanceDue > 0.01 ? (_nextPaymentDate ?? DateTime.now().add(const Duration(days: 30))) : null,
status: widget.existingInvoice != null
? (isFullyPaid ? 'PAID' : (validAmountPaid > 0.01 ? 'PARTIAL' : widget.existingInvoice!.status))
: determinedStatus,
notes: _notesCtrl.text.trim().isEmpty ? null : _notesCtrl.text.trim(),
invoiceUrl: finalInvoiceUrl,
isEmi: _isEmi,