diff --git a/lib/app/pages/order/order_page.dart b/lib/app/pages/order/order_page.dart index d5fe156..79f7f04 100644 --- a/lib/app/pages/order/order_page.dart +++ b/lib/app/pages/order/order_page.dart @@ -159,6 +159,91 @@ class _OrderViewState extends State<_OrderView> { if (result != null) vm.transferOrder(result); } + Future showAcceptOrderDialog() async { + OrderViewModel vm = context.read(); + List? result = await showDialog>( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + Order order = vm.state.order; + String weight = order.weight != null ? Format.numberStr(order.weight! / 1000) : ''; + String volume = order.volume != null ? Format.numberStr(order.volume! / 1000000) : ''; + TextEditingController _weightDialogController = TextEditingController(text: weight); + TextEditingController _volumeDialogController = TextEditingController(text: volume); + bool? hasDocuments = !order.documentsReturn; + TextStyle textStyle = const TextStyle(fontSize: 14); + + return StatefulBuilder( + builder: (context, setState) { + return AlertDialog( + title: const Text('Подтвердите заказ'), + content: SingleChildScrollView( + child: ListBody( + children: [ + InfoRow( + padding: EdgeInsets.zero, + title: Text('Вес, кг', style: textStyle), + trailing: TextFormField( + maxLines: 1, + autocorrect: false, + controller: _weightDialogController, + style: textStyle, + keyboardType: const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration(contentPadding: EdgeInsets.only()) + ), + ), + InfoRow( + padding: EdgeInsets.zero, + title: Text('Объем, м3', style: textStyle), + trailing: TextFormField( + maxLines: 1, + autocorrect: false, + controller: _volumeDialogController, + style: textStyle, + keyboardType: const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration(contentPadding: EdgeInsets.only()) + ) + ), + !order.documentsReturn ? + Container() : + InfoRow( + padding: EdgeInsets.zero, + title: Text('Документы', style: textStyle), + trailing: DropdownButton( + isExpanded: true, + menuMaxHeight: 200, + value: hasDocuments, + items: [true, false].map((e) => DropdownMenuItem( + value: e, + child: Text(e ? 'Да' : 'Нет', style: textStyle) + )).toList(), + onChanged: (bool? newVal) => setState(() => hasDocuments = newVal) + ) + ) + ] + ) + ), + actions: [ + TextButton( + child: const Text(Strings.ok), + onPressed: () { + Navigator.of(context).pop( + [hasDocuments, _weightDialogController.text, _volumeDialogController.text] + ); + } + ), + TextButton(child: const Text(Strings.cancel), onPressed: () => Navigator.of(context).pop(null)) + ], + ); + } + ); + }); + + if (result != null) { + vm.acceptOrder(result[0], result[1], result[2]); + } + } + void showMessage(String message) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message),)); } @@ -202,7 +287,7 @@ class _OrderViewState extends State<_OrderView> { ), InfoRow( title: const Text('Вес, кг'), - trailing: !vm.state.deliverable ? Text(weight) : TextFormField( + trailing: !vm.state.scanned ? Text(weight) : TextFormField( maxLines: 1, autocorrect: false, controller: _weightController, @@ -214,7 +299,7 @@ class _OrderViewState extends State<_OrderView> { ), InfoRow( title: const Text('Объем, м3'), - trailing: !vm.state.deliverable ? Text(volume) : TextFormField( + trailing: !vm.state.scanned ? Text(volume) : TextFormField( maxLines: 1, autocorrect: false, controller: _volumeController, @@ -269,7 +354,7 @@ class _OrderViewState extends State<_OrderView> { children: vm.state.lines.map((e) => _buildOrderLineTile(context, e)).toList() ), orderActions(context), - orderDeliveryActions(context) + orderPickupActions(context) ]; } @@ -277,13 +362,14 @@ class _OrderViewState extends State<_OrderView> { OrderViewModel vm = context.read(); List actions = [ - !(vm.state.transferAcceptable) ? null : TextButton( - onPressed: vm.acceptTransferOrder, + !(vm.state.storageTransferAcceptable) ? null : TextButton( + onPressed: vm.acceptStorageTransferOrder, child: Column(children: const [Icon(Icons.how_to_reg_sharp, color: Colors.black), Text('Принять')]), style: _buttonStyle ), !vm.state.acceptable ? null : TextButton( - onPressed: vm.tryAcceptOrder, + onPressed: showAcceptOrderDialog, + //onPressed: vm.tryAcceptOrder, child: Column(children: const [Icon(Icons.fact_check, color: Colors.black), Text('Приемка')]), style: _buttonStyle ), @@ -304,10 +390,15 @@ class _OrderViewState extends State<_OrderView> { ); } - Widget orderDeliveryActions(BuildContext context) { + Widget orderPickupActions(BuildContext context) { OrderViewModel vm = context.read(); List actions = [ + !(vm.state.transferAcceptable) ? null : TextButton( + onPressed: vm.acceptTransferOrder, + child: Column(children: const [Icon(Icons.how_to_reg_sharp, color: Colors.black), Text('Принять')]), + style: _buttonStyle + ), !vm.state.deliverable ? null : TextButton( onPressed: vm.tryConfirmOrder, child: Column(children: const [Icon(Icons.assignment_turned_in, color: Colors.black), Text('Выдать')]), diff --git a/lib/app/pages/order/order_state.dart b/lib/app/pages/order/order_state.dart index bcd5aa7..cb551f9 100644 --- a/lib/app/pages/order/order_state.dart +++ b/lib/app/pages/order/order_state.dart @@ -36,7 +36,8 @@ class OrderState { List get lines => orderWithLines.lines; Order get order => orderWithLines.order; - bool get transferAcceptable => scanned && (storageAccess || pickupPointAccess); + bool get transferAcceptable => scanned && pickupPointAccess; + bool get storageTransferAcceptable => scanned && storageAccess; bool get transferable => scanned && storageAccess; bool get acceptable => scanned && storageAccess && order.firstMovementDate == null; bool get deliverable => scanned && pickupPointAccess && order.delivered == null; diff --git a/lib/app/pages/order/order_view_model.dart b/lib/app/pages/order/order_view_model.dart index c1cdc33..dc349ec 100644 --- a/lib/app/pages/order/order_view_model.dart +++ b/lib/app/pages/order/order_view_model.dart @@ -35,7 +35,7 @@ class OrderViewModel extends PageViewModel { } Future updateWeight(String value) async { - double? parsedWeight = double.tryParse(value.replaceAll(',', '.')); + double? parsedWeight = double.tryParse(value.replaceAll(',', '.')); if (parsedWeight == null) { emit(state.copyWith(status: OrderStateStatus.failure, message: 'Указано не корректное число')); @@ -43,16 +43,14 @@ class OrderViewModel extends PageViewModel { } try { - int newWeight = (parsedWeight * 1000).toInt(); - - await _updateOrder({'weight': newWeight}); + await _updateOrder({'weight': (parsedWeight * 1000).toInt()}); } on AppError catch(e) { emit(state.copyWith(status: OrderStateStatus.failure, message: e.message)); } } Future updateVolume(String value) async { - double? parsedVolume = double.tryParse(value.replaceAll(',', '.')); + double? parsedVolume = double.tryParse(value.replaceAll(',', '.')); if (parsedVolume == null) { emit(state.copyWith(status: OrderStateStatus.failure, message: 'Указано не корректное число')); @@ -60,9 +58,7 @@ class OrderViewModel extends PageViewModel { } try { - int newVolume = (parsedVolume * 1000000).toInt(); - - await _updateOrder({'volume': newVolume}); + await _updateOrder({'volume': (parsedVolume * 1000000).toInt()}); } on AppError catch(e) { emit(state.copyWith(status: OrderStateStatus.failure, message: e.message)); } @@ -80,7 +76,7 @@ class OrderViewModel extends PageViewModel { } } - Future acceptOrder(bool confirmed) async { + Future acceptOrder(bool confirmed, String weightStr, String volumeStr) async { if (!confirmed) { if (state.order.documentsReturn) { emit(state.copyWith( @@ -92,9 +88,18 @@ class OrderViewModel extends PageViewModel { return; } + double? parsedWeight = double.tryParse(weightStr.replaceAll(',', '.')); + double? parsedVolume = double.tryParse(volumeStr.replaceAll(',', '.')); + + if (parsedVolume == null || parsedWeight == null) { + emit(state.copyWith(status: OrderStateStatus.failure, message: 'Указано не корректное число')); + return; + } + emit(state.copyWith(status: OrderStateStatus.inProgress)); try { + await _updateOrder({'volume': (parsedVolume * 1000000).toInt(), 'weight': (parsedWeight * 1000).toInt()}); await _acceptOrder(); emit(state.copyWith(status: OrderStateStatus.success, message: 'Заказ успешно принят')); @@ -103,6 +108,18 @@ class OrderViewModel extends PageViewModel { } } + Future acceptStorageTransferOrder() async { + emit(state.copyWith(status: OrderStateStatus.inProgress)); + + try { + await _acceptStorageTransferOrder(); + + emit(state.copyWith(status: OrderStateStatus.success, message: 'Заказ успешно принят')); + } on AppError catch(e) { + emit(state.copyWith(status: OrderStateStatus.failure, message: e.message)); + } + } + Future acceptTransferOrder() async { emit(state.copyWith(status: OrderStateStatus.inProgress)); @@ -155,20 +172,6 @@ class OrderViewModel extends PageViewModel { )); } - void tryAcceptOrder() { - if (state.order.documentsReturn) { - emit(state.copyWith( - status: OrderStateStatus.needUserConfirmation, - confirmationCallback: acceptOrder, - message: 'Есть ли документы к заказу?', - )); - - return; - } - - acceptOrder(true); - } - void tryConfirmOrder() { emit(state.copyWith( status: OrderStateStatus.needUserConfirmation, @@ -275,6 +278,19 @@ class OrderViewModel extends PageViewModel { } } + Future _acceptStorageTransferOrder() async { + try { + ApiOrder newOrder = await Api(storage: app.storage).acceptStorageTransferOrder(id: state.order.id); + + await _saveApiOrder(newOrder); + } on ApiException catch(e) { + throw AppError(e.errorMsg); + } catch(e, trace) { + await app.reportError(e, trace); + throw AppError(Strings.genericErrorMsg); + } + } + Future _acceptTransferOrder() async { try { ApiOrder newOrder = await Api(storage: app.storage).acceptTransferOrder(id: state.order.id); diff --git a/lib/app/services/api.dart b/lib/app/services/api.dart index cddfb39..d9a04ad 100644 --- a/lib/app/services/api.dart +++ b/lib/app/services/api.dart @@ -99,6 +99,17 @@ class Api { return ApiOrder.fromJson(orderData); } + Future acceptStorageTransferOrder({ + required int id + }) async { + final orderData = await _sendRequest((dio) => dio.post( + 'v1/logisto/accept_storage_transfer_order', + data: { 'id': id } + )); + + return ApiOrder.fromJson(orderData); + } + Future acceptTransferOrder({ required int id }) async { diff --git a/lib/app/widgets/info_row.dart b/lib/app/widgets/info_row.dart index 7967a40..c141455 100644 --- a/lib/app/widgets/info_row.dart +++ b/lib/app/widgets/info_row.dart @@ -1,11 +1,13 @@ import 'package:flutter/material.dart'; class InfoRow extends StatelessWidget { + final EdgeInsets padding; final Widget? title; final Widget? trailing; const InfoRow({ Key? key, + this.padding = const EdgeInsets.symmetric(horizontal: 8), this.title, this.trailing }) : super(key: key); @@ -13,7 +15,7 @@ class InfoRow extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: padding, child: Row( children: [ Flexible(