barcode_scanner/lib/pages/operation/reception/reception_details_page_model.dart
mandreshope c231790f59 feat: Implements backorder confirmation flow for receptions
Corrects API endpoints for creating, processing with, and processing without backorder confirmations.

Adds a new `isBackorder` getter to stock picking records for identifying backordered items, and improves the robustness of the `isDone` getter.

Integrates backorder detection into the reception validation process, prompting a dedicated confirmation dialog when a backorder is present.

Introduces new state management and methods (`withBackorder`, `withoutBackorder`) in the reception details model to handle the backorder confirmation logic.

Enhances the primary button component with a `backgroundColor` property for greater customization.
2025-08-04 09:37:26 +03:00

183 lines
5.7 KiB
Dart

import 'package:e_scan/backend/api/api_calls.dart';
import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:e_scan/backend/objectbox/objectbox_manager.dart';
import 'package:e_scan/backend/schema/stock_picking/update_move_line_dto.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'reception_details_page_model.freezed.dart';
final receptionDetailsPageModelProvider =
StateNotifierProvider.autoDispose<
ReceptionDetailsPageModel,
ReceptionDetailsPageState
>((ref) {
return ReceptionDetailsPageModel();
});
class ReceptionDetailsPageModel
extends StateNotifier<ReceptionDetailsPageState> {
ReceptionDetailsPageModel() : super(const ReceptionDetailsPageState());
Future getReceptionById({required int id}) async {
try {
final stockPickingRecords = objectboxManager.store
.box<StockPickingRecordEntity>();
state = state.copyWith(loading: true);
final entity = stockPickingRecords.get(id);
state = state.copyWith(loading: false, reception: entity);
} catch (e) {
state = state.copyWith(loading: false);
}
}
Future save({
required int receptionId,
VoidCallback? onSuccess,
VoidCallback? onError,
}) async {
try {
state = state.copyWith(saveLoading: true);
final stockPickingRecords = objectboxManager.store
.box<StockPickingRecordEntity>();
final stockPikingEntity = stockPickingRecords.get(receptionId);
final moveLinesDto =
stockPikingEntity?.moveLineIdsWithoutPackage
.map(
(m) => UpdateMoveLineDto(
operation: 1,
moveLineId: m.id,
values: {"quantity": m.quantity},
),
)
.toList() ??
[];
final res = await ApiCalls.updateAllMoveLineOnStockPicking(
stockPickingId: receptionId,
moveLineDto: moveLinesDto,
);
if (res) {
stockPikingEntity?.synchronized = true;
stockPickingRecords.put(stockPikingEntity!);
getReceptionById(id: receptionId);
onSuccess?.call();
} else {
onError?.call();
}
state = state.copyWith(saveLoading: false);
} catch (e) {
onError?.call();
state = state.copyWith(saveLoading: false);
}
}
Future validate({
required int receptionId,
VoidCallback? onSuccess,
VoidCallback? onError,
}) async {
await save(receptionId: receptionId);
try {
final stockPickingRecords = objectboxManager.store
.box<StockPickingRecordEntity>();
final stockPikingEntity = stockPickingRecords.get(receptionId);
state = state.copyWith(validateLoading: true);
final res = await ApiCalls.validateStockPicking(
stockPickingId: receptionId,
);
if (res) {
onSuccess?.call();
stockPikingEntity?.synchronized = true;
stockPikingEntity?.state = 'done';
stockPickingRecords.put(stockPikingEntity!);
getReceptionById(id: receptionId);
} else {
onError?.call();
}
state = state.copyWith(validateLoading: false);
} catch (e) {
onError?.call();
state = state.copyWith(validateLoading: false);
}
}
Future withBackorder({
required int receptionId,
VoidCallback? onSuccess,
VoidCallback? onError,
}) async {
await save(receptionId: receptionId);
try {
state = state.copyWith(withBackorderLoading: true);
final createBackorderConfirmationId =
await ApiCalls.createBackorderConfirmation(
stockPickingId: receptionId,
);
if (createBackorderConfirmationId != null) {
final res = await ApiCalls.withBackorder(
stockPickingId: receptionId,
createBackorderConfirmationId: createBackorderConfirmationId,
);
if (res) {
await getReceptionById(id: receptionId);
onSuccess?.call();
} else {
onError?.call();
}
} else {
onError?.call();
}
state = state.copyWith(withBackorderLoading: false);
} catch (e) {
onError?.call();
state = state.copyWith(withBackorderLoading: false);
}
}
Future withoutBackorder({
required int receptionId,
VoidCallback? onSuccess,
VoidCallback? onError,
}) async {
await save(receptionId: receptionId);
try {
state = state.copyWith(withBackorderLoading: true);
final createBackorderConfirmationId =
await ApiCalls.createBackorderConfirmation(
stockPickingId: receptionId,
);
if (createBackorderConfirmationId != null) {
final res = await ApiCalls.withoutBackorder(
stockPickingId: receptionId,
createBackorderConfirmationId: createBackorderConfirmationId,
);
if (res) {
await getReceptionById(id: receptionId);
onSuccess?.call();
} else {
onError?.call();
}
} else {
onError?.call();
}
state = state.copyWith(withBackorderLoading: false);
} catch (e) {
onError?.call();
state = state.copyWith(withBackorderLoading: false);
}
}
}
@freezed
abstract class ReceptionDetailsPageState with _$ReceptionDetailsPageState {
const factory ReceptionDetailsPageState({
StockPickingRecordEntity? reception,
@Default(false) bool loading,
@Default(false) bool validateLoading,
@Default(false) bool saveLoading,
@Default(false) bool withBackorderLoading,
@Default(false) bool withoutBackorderLoading,
}) = _ReceptionDetailsPageState;
}