
Introduces an `isDraft` property to `StockPickingRecordEntity` to mark receptions with local modifications. Automatically sets a reception to draft status when a product's quantity is incremented via scanning. Displays a 'Brouillon' chip on reception cards to provide visual feedback for draft operations. Ensures reception details are refreshed after scanning to reflect the updated draft status and provides immediate error feedback when no product is found during a scan.
141 lines
4.1 KiB
Dart
141 lines
4.1 KiB
Dart
import 'package:e_scan/themes/app_theme.dart';
|
||
import 'package:flutter/material.dart';
|
||
|
||
class StockPickingCard extends StatelessWidget {
|
||
const StockPickingCard({
|
||
super.key,
|
||
required this.reference,
|
||
required this.from,
|
||
required this.to,
|
||
required this.contact,
|
||
required this.origin,
|
||
required this.status,
|
||
required this.isDone,
|
||
this.isDraft = false,
|
||
this.margin,
|
||
});
|
||
final bool isDone;
|
||
final bool isDraft;
|
||
final String? reference;
|
||
final String? from;
|
||
final String? to;
|
||
final String? contact;
|
||
final String? origin;
|
||
final String? status;
|
||
final EdgeInsetsGeometry? margin;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Card(
|
||
elevation: 3,
|
||
color: AppTheme.of(context).primaryBackground,
|
||
margin: margin ?? const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: Row(
|
||
spacing: 8,
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
const Icon(Icons.receipt_long, color: Colors.blue),
|
||
Expanded(
|
||
child: Text(
|
||
reference ?? 'Référence inconnue',
|
||
style: const TextStyle(
|
||
fontSize: 18,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
if (isDraft)
|
||
Chip(
|
||
backgroundColor: Colors.red,
|
||
label: Row(
|
||
spacing: 8,
|
||
children: [
|
||
Icon(Icons.cloud_off_outlined, color: Colors.white),
|
||
Text(
|
||
'Brouillon',
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 12),
|
||
_infoStateRow(isDone, "Statut", status),
|
||
_infoRow(Icons.call_made, "De", from),
|
||
_infoRow(Icons.call_received, "Vers", to),
|
||
_infoRow(Icons.person, "Contact", contact),
|
||
_infoRow(Icons.insert_drive_file, "Document d’origine", origin),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _infoStateRow(bool isDone, String label, String? value) {
|
||
var color = Colors.grey[700];
|
||
var icon = Icons.refresh;
|
||
if (isDone) {
|
||
icon = Icons.check_circle;
|
||
color = Colors.green;
|
||
}
|
||
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||
child: Row(
|
||
children: [
|
||
Icon(icon, size: 20, color: color),
|
||
const SizedBox(width: 8),
|
||
Text(
|
||
"$label : ",
|
||
style: TextStyle(fontWeight: FontWeight.bold, color: color),
|
||
),
|
||
Expanded(
|
||
child: Text(
|
||
(value ?? "-").toUpperCase(),
|
||
style: TextStyle(color: color, fontWeight: FontWeight.bold),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _infoRow(IconData icon, String label, String? value) {
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||
child: Row(
|
||
children: [
|
||
Icon(icon, size: 20, color: Colors.grey[700]),
|
||
const SizedBox(width: 8),
|
||
Text(
|
||
"$label : ",
|
||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||
),
|
||
Expanded(
|
||
child: Text(
|
||
(value ?? "-").toUpperCase(),
|
||
style: const TextStyle(color: Colors.black87),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|