barcode_scanner/lib/pages/operation/reception/reception_details_page.dart
mandreshope ba1d7a6264 refactor: Refines reception validation and quick actions
Allows reception validation regardless of its synchronization status, enabling more flexible use cases.

Simplifies the quick actions available on the reception list page by removing the 'Add' and 'Scan' buttons, retaining only the 'Search' option.

Adds vertical spacing before the search button within the QuickActionComponent for improved visual layout.
2025-07-31 14:25:03 +03:00

213 lines
9.4 KiB
Dart

import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:e_scan/components/components.dart';
import 'package:e_scan/pages/operation/reception/reception_details_page_model.dart';
import 'package:e_scan/router/go_secure_router_builder.dart';
import 'package:e_scan/themes/app_theme.dart';
import 'package:e_scan/utils/utils.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
class ReceptionDetailsPage extends ConsumerStatefulWidget {
const ReceptionDetailsPage({super.key, required this.receptionId});
final int receptionId;
@override
ConsumerState<ReceptionDetailsPage> createState() =>
_ReceptionDetailsPageState();
}
class _ReceptionDetailsPageState extends ConsumerState<ReceptionDetailsPage> {
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
ref
.read(receptionDetailsPageModelProvider.notifier)
.getReceptionById(id: widget.receptionId);
});
}
@override
Widget build(BuildContext context) {
final state = ref.watch(receptionDetailsPageModelProvider);
final reception = state.reception;
return Scaffold(
backgroundColor: AppTheme.of(context).primaryBackground,
appBar: MainAppbarComponent(
leading: BackButton(color: AppTheme.of(context).white),
title: "Réceptions",
subTitle: "Opérations d'Entrepôt",
),
body: state.loading
? Center(child: LoadingProgressComponent())
: RefreshIndicator(
color: AppTheme.of(context).white,
backgroundColor: AppTheme.of(context).primary,
onRefresh: () async {
await ref
.read(receptionDetailsPageModelProvider.notifier)
.getReceptionById(id: widget.receptionId);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: [
const SizedBox(height: 16),
if (reception?.isDone == false) ...[
QuickActionComponent(
onTapValidateReception: () {
ref
.read(receptionDetailsPageModelProvider.notifier)
.validate(
receptionId: widget.receptionId,
onSuccess: () {
Toast.showSuccess(
'Réception validée avec succès.',
);
},
onError: () {
Toast.showError(
'Connexion impossible. Les données seront synchronisées plus tard.',
);
},
);
},
validateReceptionLoading: state.validateLoading,
syncReceptionLoading: state.saveLoading,
onTapSyncReception: reception?.synchronized == false
? () {
ref
.read(
receptionDetailsPageModelProvider
.notifier,
)
.save(
receptionId: widget.receptionId,
onSuccess: () {
Toast.showSuccess(
'Les données sont synchronisées.',
);
},
onError: () {
Toast.showError(
'Connexion impossible. Les données seront synchronisées plus tard.',
);
},
);
}
: null,
onTapScan: () {
final id = reception?.id;
if (id == null) return;
ReceptionScanRoute(receptionId: id)
.push(context)
.then(
(v) => ref
.read(
receptionDetailsPageModelProvider
.notifier,
)
.getReceptionById(id: widget.receptionId),
);
},
),
const SizedBox(height: 16),
],
Text(
'Détails réception',
style: AppTheme.of(
context,
).bodyMedium.copyWith(fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
StockPickingCard(
synchronized: reception?.synchronized == true,
isDone: reception?.isDone == true,
margin: EdgeInsets.symmetric(horizontal: 5),
reference: reception?.name ?? '',
from: reception?.locationId.target?.completeName,
to: reception?.locationDestId.target?.completeName,
contact: reception?.partnerId.target?.displayName,
origin: reception?.origin,
status: reception?.state,
),
SizedBox(height: 20),
Text(
'Produits',
style: AppTheme.of(
context,
).bodyMedium.copyWith(fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
...reception?.moveIdsWithoutPackage
.map(
(move) => Card(
color: AppTheme.of(context).primaryBackground,
child: ListTile(
title: Text(
move.productId.target?.displayName ?? '',
style: TextStyle(color: Colors.black),
),
subtitle: Wrap(
spacing: 5,
children: [
Chip(
backgroundColor: AppTheme.of(
context,
).secondaryBackground,
label: Text(
"Qté demandée: ${move.productUomQty}",
),
),
Chip(
backgroundColor: AppTheme.of(
context,
).secondaryBackground,
label: Text(
"Qté reçue: ${move.quantity}",
),
),
Chip(
backgroundColor: AppTheme.of(
context,
).secondaryBackground,
label: Text(
"Ecart: ${move.ecart}",
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
),
)
.toList() ??
[],
],
),
),
),
floatingActionButton: reception?.isDone == false
? FloatingActionButton(
backgroundColor: AppTheme.of(context).primary,
onPressed: () {
final id = reception?.id;
if (id == null) return;
ReceptionScanRoute(receptionId: id)
.push(context)
.then(
(v) => ref
.read(receptionDetailsPageModelProvider.notifier)
.getReceptionById(id: widget.receptionId),
);
},
child: Icon(Icons.qr_code, color: AppTheme.of(context).white),
)
: null,
);
}
}