barcode_scanner/lib/components/stock_picking_card_component.dart
your-name 18f74daae4 feat: Implement explicit synchronization and validation
Refactors the reception process to provide clearer control over data synchronization and validation.

- Replaces the `isDraft` property with `synchronized` in `StockPickingRecordEntity` to accurately represent the local data's sync status with the backend.
- Introduces a new API endpoint and corresponding logic for `validateStockPicking`, allowing finalization of receptions.
- Splits the "Save" action into "Synchronize data" and "Validate reception" on the details page. "Validate" now implicitly performs a synchronization first.
- Updates UI elements (cards, quick actions) to reflect the new synchronization state and expose the new actions.
- Corrects a typo in the `updateAllMoveLineOnStockPicking` API method name.
- Improves local data update logic for scanned items, marking them as unsynchronized.
2025-07-31 02:34:50 +03:00

141 lines
4.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.synchronized = true,
this.margin,
});
final bool isDone;
final bool synchronized;
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 (!synchronized)
Chip(
backgroundColor: Colors.red,
label: Row(
spacing: 8,
children: [
Icon(Icons.cloud_off_outlined, color: Colors.white),
Text(
'Non synchronisé',
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 dorigine", 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),
),
),
],
),
);
}
}