
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.
213 lines
9.4 KiB
Dart
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,
|
|
);
|
|
}
|
|
}
|