Инвентаризация ++
parent
94db86ee66
commit
e461fb5662
|
|
@ -0,0 +1,38 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'good_item.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable(explicitToJson: true)
|
||||||
|
class GoodInventarization {
|
||||||
|
GoodInventarization({
|
||||||
|
required this.id,
|
||||||
|
required this.eaccGoodId,
|
||||||
|
required this.name,
|
||||||
|
required this.cnt,
|
||||||
|
required this.price,
|
||||||
|
required this.cntBuh,
|
||||||
|
required this.priceBuh,
|
||||||
|
this.articul,
|
||||||
|
this.category,
|
||||||
|
this.ean13,
|
||||||
|
});
|
||||||
|
|
||||||
|
int id;
|
||||||
|
@JsonKey(name: 'eacc_good_id')
|
||||||
|
int eaccGoodId;
|
||||||
|
double cnt;
|
||||||
|
double price;
|
||||||
|
@JsonKey(name: 'cnt_buh')
|
||||||
|
double cntBuh;
|
||||||
|
@JsonKey(name: 'price_buh')
|
||||||
|
double priceBuh;
|
||||||
|
String name;
|
||||||
|
int? articul;
|
||||||
|
String? ean13;
|
||||||
|
String? category;
|
||||||
|
|
||||||
|
factory GoodInventarization.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$GoodInventarizationFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$GoodInventarizationToJson(this);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'good_item.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
GoodInventarization _$GoodInventarizationFromJson(Map<String, dynamic> json) =>
|
||||||
|
GoodInventarization(
|
||||||
|
id: json['id'] as int,
|
||||||
|
eaccGoodId: json['eacc_good_id'] as int,
|
||||||
|
name: json['name'] as String,
|
||||||
|
cnt: (json['cnt'] as num).toDouble(),
|
||||||
|
price: (json['price'] as num).toDouble(),
|
||||||
|
cntBuh: (json['cnt_buh'] as num).toDouble(),
|
||||||
|
priceBuh: (json['price_buh'] as num).toDouble(),
|
||||||
|
articul: json['articul'] as int?,
|
||||||
|
category: json['category'] as String?,
|
||||||
|
ean13: json['ean13'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$GoodInventarizationToJson(
|
||||||
|
GoodInventarization instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'eacc_good_id': instance.eaccGoodId,
|
||||||
|
'cnt': instance.cnt,
|
||||||
|
'price': instance.price,
|
||||||
|
'cnt_buh': instance.cntBuh,
|
||||||
|
'price_buh': instance.priceBuh,
|
||||||
|
'name': instance.name,
|
||||||
|
'articul': instance.articul,
|
||||||
|
'ean13': instance.ean13,
|
||||||
|
'category': instance.category,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:satu/core/models/inventarization/good_item/good_item.dart';
|
||||||
|
|
||||||
|
part 'invetarization_good_list.g.dart';
|
||||||
|
@JsonSerializable(explicitToJson: true)
|
||||||
|
class InventarizationGoodList {
|
||||||
|
InventarizationGoodList({
|
||||||
|
required this.goodsList
|
||||||
|
});
|
||||||
|
|
||||||
|
@JsonKey(name: 'goods_list')
|
||||||
|
List<GoodInventarization> goodsList;
|
||||||
|
|
||||||
|
factory InventarizationGoodList.fromJson(Map<String, dynamic> json) => _$InventarizationGoodListFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$InventarizationGoodListToJson(this);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'invetarization_good_list.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
InventarizationGoodList _$InventarizationGoodListFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
InventarizationGoodList(
|
||||||
|
goodsList: (json['goods_list'] as List<dynamic>)
|
||||||
|
.map((e) => GoodInventarization.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$InventarizationGoodListToJson(
|
||||||
|
InventarizationGoodList instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'goods_list': instance.goodsList.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
|
@ -48,6 +48,7 @@ class ResponseOriginal {
|
||||||
int? page;
|
int? page;
|
||||||
int? perpage;
|
int? perpage;
|
||||||
List<dynamic>? data;
|
List<dynamic>? data;
|
||||||
|
dynamic result;
|
||||||
Map<String, List<String>>? errors;
|
Map<String, List<String>>? errors;
|
||||||
String? message;
|
String? message;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ ResponseOriginal _$ResponseOriginalFromJson(Map<String, dynamic> json) =>
|
||||||
..page = json['page'] as int?
|
..page = json['page'] as int?
|
||||||
..perpage = json['perpage'] as int?
|
..perpage = json['perpage'] as int?
|
||||||
..data = json['data'] as List<dynamic>?
|
..data = json['data'] as List<dynamic>?
|
||||||
|
..result = json['result']
|
||||||
..errors = (json['errors'] as Map<String, dynamic>?)?.map(
|
..errors = (json['errors'] as Map<String, dynamic>?)?.map(
|
||||||
(k, e) =>
|
(k, e) =>
|
||||||
MapEntry(k, (e as List<dynamic>).map((e) => e as String).toList()),
|
MapEntry(k, (e as List<dynamic>).map((e) => e as String).toList()),
|
||||||
|
|
@ -45,6 +46,7 @@ Map<String, dynamic> _$ResponseOriginalToJson(ResponseOriginal instance) =>
|
||||||
'page': instance.page,
|
'page': instance.page,
|
||||||
'perpage': instance.perpage,
|
'perpage': instance.perpage,
|
||||||
'data': instance.data,
|
'data': instance.data,
|
||||||
|
'result': instance.result,
|
||||||
'errors': instance.errors,
|
'errors': instance.errors,
|
||||||
'message': instance.message,
|
'message': instance.message,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ class ApiService extends BaseService {
|
||||||
// log.i(host);
|
// log.i(host);
|
||||||
// log.i(url);
|
// log.i(url);
|
||||||
// log.i(headers);
|
// log.i(headers);
|
||||||
log.i(jsonEncode(requestBody));
|
//log.i(jsonEncode(requestBody));
|
||||||
log.i(jsonEncode(response.body));
|
//log.i(jsonEncode(response.body));
|
||||||
}
|
}
|
||||||
return response.body;
|
return response.body;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ class DialogService {
|
||||||
|
|
||||||
Future<DialogResponse> showConfirmationDialogInput({
|
Future<DialogResponse> showConfirmationDialogInput({
|
||||||
required String title,
|
required String title,
|
||||||
required String requestPrice,
|
|
||||||
required String requestCount,
|
required String requestCount,
|
||||||
|
String? requestPrice,
|
||||||
String? description,
|
String? description,
|
||||||
String confirmationTitle = 'ПОДТВЕРДИТЬ',
|
String confirmationTitle = 'ПОДТВЕРДИТЬ',
|
||||||
String cancelTitle = 'Отмена',
|
String cancelTitle = 'Отмена',
|
||||||
|
|
|
||||||
|
|
@ -11,24 +11,26 @@ import 'package:satu/core/utils/locator.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
import 'db_service.dart';
|
import 'db_service.dart';
|
||||||
|
|
||||||
|
Good goodResponseToGood(GoodResponseEntity response) {
|
||||||
|
return Good()
|
||||||
|
..id = response.id
|
||||||
|
..name = response.name
|
||||||
|
..basePrice = response.basePrice
|
||||||
|
..optPrice = response.optPrice
|
||||||
|
..price = response.price
|
||||||
|
..articul = response.articul
|
||||||
|
..categoryId = response.categoryId
|
||||||
|
..categoryName = response.categoryName
|
||||||
|
..divisible = response.divisible
|
||||||
|
..ean = response.ean13
|
||||||
|
..appCompanyId = response.appCompanyId;
|
||||||
|
}
|
||||||
|
|
||||||
class DictionaryService extends BaseService {
|
class DictionaryService extends BaseService {
|
||||||
final ApiService _api = locator<ApiService>();
|
final ApiService _api = locator<ApiService>();
|
||||||
final DbService _db = locator<DbService>();
|
final DbService _db = locator<DbService>();
|
||||||
|
|
||||||
Good goodResponseToGood(GoodResponseEntity response) {
|
|
||||||
return Good()
|
|
||||||
..id = response.id
|
|
||||||
..name = response.name
|
|
||||||
..basePrice = response.basePrice
|
|
||||||
..optPrice = response.optPrice
|
|
||||||
..price = response.price
|
|
||||||
..articul = response.articul
|
|
||||||
..categoryId = response.categoryId
|
|
||||||
..categoryName = response.categoryName
|
|
||||||
..divisible = response.divisible
|
|
||||||
..ean = response.ean13
|
|
||||||
..appCompanyId = response.appCompanyId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Category categoryResponseToCategory(CategoryResponse response) {
|
Category categoryResponseToCategory(CategoryResponse response) {
|
||||||
return Category()
|
return Category()
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import 'package:satu/core/base/base_service.dart';
|
import 'package:satu/core/base/base_service.dart';
|
||||||
import 'package:satu/core/models/inventarization/inventarization_response.dart';
|
import 'package:satu/core/models/inventarization/invetarization_good_list/invetarization_good_list.dart';
|
||||||
|
import 'package:satu/core/models/inventarization/response/inventarization_response.dart';
|
||||||
import 'package:satu/core/utils/locator.dart';
|
import 'package:satu/core/utils/locator.dart';
|
||||||
|
|
||||||
|
import '../models/inventarization/good_item/good_item.dart';
|
||||||
import '../models/response/response_entity.dart';
|
import '../models/response/response_entity.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
|
|
||||||
class InventarizationService extends BaseService {
|
class InventarizationService extends BaseService {
|
||||||
final ApiService _api = locator<ApiService>();
|
final ApiService _api = locator<ApiService>();
|
||||||
|
|
||||||
Future<List<InventarizationResponse>> getList(
|
Future<List<InventarizationResponse>> getList(
|
||||||
|
|
@ -17,12 +19,13 @@ class InventarizationService extends BaseService {
|
||||||
'perpage': perpage
|
'perpage': perpage
|
||||||
};
|
};
|
||||||
|
|
||||||
ResponseEntity categories = await _api
|
ResponseEntity categories = await _api.postRequest('/goods_inventory_get',
|
||||||
.postRequest('/goods_inventory_get', requestBody: requestBody);
|
requestBody: requestBody);
|
||||||
if (categories.original.data != null &&
|
if (categories.original.data != null &&
|
||||||
categories.original.data!.isNotEmpty) {
|
categories.original.data!.isNotEmpty) {
|
||||||
for (final dynamic map in categories.original.data!) {
|
for (final dynamic map in categories.original.data!) {
|
||||||
final InventarizationResponse item = InventarizationResponse.fromJson(map);
|
final InventarizationResponse item =
|
||||||
|
InventarizationResponse.fromJson(map);
|
||||||
list.add(item);
|
list.add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,4 +35,63 @@ class InventarizationService extends BaseService {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<GoodInventarization>> getGoodByInventarizationId(
|
||||||
|
{required int page, required int perpage, required int id}) async {
|
||||||
|
List<GoodInventarization> list = [];
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> requestBody = <String, dynamic>{
|
||||||
|
'page': page,
|
||||||
|
'perpage': perpage,
|
||||||
|
'id': id
|
||||||
|
};
|
||||||
|
|
||||||
|
ResponseEntity categories = await _api.postRequest(
|
||||||
|
'/goods_inventory_get_edit_form_data',
|
||||||
|
requestBody: requestBody);
|
||||||
|
if (categories.original.result != null) {
|
||||||
|
InventarizationGoodList listResponse = InventarizationGoodList.fromJson(categories.original.result);
|
||||||
|
list.addAll(listResponse.goodsList);
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
log.e('getList', e, stack);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> addGoodToList(int inventoryId, int? goodId) async {
|
||||||
|
bool result = false;
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> requestBody = <String, dynamic>{
|
||||||
|
'page': 1,
|
||||||
|
'perpage': 1,
|
||||||
|
'id': inventoryId,
|
||||||
|
'good_id' : goodId
|
||||||
|
};
|
||||||
|
ResponseEntity response = await _api.postRequest(
|
||||||
|
'/goods_inventory_select_item',
|
||||||
|
requestBody: requestBody);
|
||||||
|
result = response.original.result != null;
|
||||||
|
} catch (e, stack) {
|
||||||
|
log.e('getList', e, stack);
|
||||||
|
}
|
||||||
|
return result ;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> setCountToItem(int inventoryId, int inventoryItemId, double value) async {
|
||||||
|
bool result = false;
|
||||||
|
try {
|
||||||
|
final Map<String, dynamic> requestBody = <String, dynamic>{
|
||||||
|
'id': inventoryId,
|
||||||
|
'inventory_item_id' : inventoryItemId,
|
||||||
|
'cnt_buh': value
|
||||||
|
};
|
||||||
|
ResponseEntity response = await _api.postRequest(
|
||||||
|
'/goods_inventory_set_cnt_item',
|
||||||
|
requestBody: requestBody);
|
||||||
|
result = response.original.result != null;
|
||||||
|
} catch (e, stack) {
|
||||||
|
log.e('getList', e, stack);
|
||||||
|
}
|
||||||
|
return result ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,9 @@ const String goodsDictionaryViewRoute = 'goodsDictionaryViewRoute';
|
||||||
const String contragentSelectViewRoute = 'ContragentSelectViewRoute';
|
const String contragentSelectViewRoute = 'ContragentSelectViewRoute';
|
||||||
const String contragentEditRoute = 'contragentEditRoute';
|
const String contragentEditRoute = 'contragentEditRoute';
|
||||||
|
|
||||||
|
// inventarization
|
||||||
|
const String inventarizationEditRoute = 'inventarizationEditRoute';
|
||||||
|
|
||||||
// setting - ble printer
|
// setting - ble printer
|
||||||
const String settingPrinterBluetoothViewRoute = 'SettingPrinterBluetoothView';
|
const String settingPrinterBluetoothViewRoute = 'SettingPrinterBluetoothView';
|
||||||
const String settingPrinterBluetoothSelectViewRoute =
|
const String settingPrinterBluetoothSelectViewRoute =
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:satu/views/dictionaries/category/category_edit.dart';
|
||||||
import 'package:satu/views/dictionaries/category/category_select_view.dart';
|
import 'package:satu/views/dictionaries/category/category_select_view.dart';
|
||||||
import 'package:satu/views/dictionaries/contragents/contragents_edit.dart';
|
import 'package:satu/views/dictionaries/contragents/contragents_edit.dart';
|
||||||
import 'package:satu/views/dictionaries/goods/goods_edit.dart';
|
import 'package:satu/views/dictionaries/goods/goods_edit.dart';
|
||||||
|
import 'package:satu/views/inventarization/view/inventarization_edit_view.dart';
|
||||||
import 'package:satu/views/login/login_view.dart';
|
import 'package:satu/views/login/login_view.dart';
|
||||||
import 'package:satu/views/main/main_view.dart';
|
import 'package:satu/views/main/main_view.dart';
|
||||||
import 'package:satu/views/settings/printer_bluetooth/printer_encoding_select.dart';
|
import 'package:satu/views/settings/printer_bluetooth/printer_encoding_select.dart';
|
||||||
|
|
@ -19,6 +20,7 @@ import 'package:satu/views/work/views/payment/payment_view.dart';
|
||||||
import 'package:satu/views/work/views/receipt/receipt_view.dart';
|
import 'package:satu/views/work/views/receipt/receipt_view.dart';
|
||||||
import 'package:satu/views/work/work_view.dart';
|
import 'package:satu/views/work/work_view.dart';
|
||||||
|
|
||||||
|
import '../core/models/inventarization/response/inventarization_response.dart';
|
||||||
import './route_names.dart';
|
import './route_names.dart';
|
||||||
|
|
||||||
Route<dynamic> generateRoute(RouteSettings settings) {
|
Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
|
|
@ -117,6 +119,14 @@ Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
transactionId: data,
|
transactionId: data,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
case inventarizationEditRoute:
|
||||||
|
final InventarizationResponse inventarizationResponse = settings.arguments! as InventarizationResponse;
|
||||||
|
return _getPageRoute(
|
||||||
|
routeName: settings.name,
|
||||||
|
viewToShow: InventarizationEditView(
|
||||||
|
item: inventarizationResponse,
|
||||||
|
),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
builder: (_) => Scaffold(
|
builder: (_) => Scaffold(
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ class _GoodsDictionaryViewState extends State<GoodsDictionaryView> {
|
||||||
itemBuilder:
|
itemBuilder:
|
||||||
(BuildContext context, GoodResponseEntity good, int index) {
|
(BuildContext context, GoodResponseEntity good, int index) {
|
||||||
return DictionaryTile(
|
return DictionaryTile(
|
||||||
|
key: Key('good_${good.id}'),
|
||||||
onPress: () async {
|
onPress: () async {
|
||||||
final dynamic result = await _navigatorService
|
final dynamic result = await _navigatorService
|
||||||
.push(goodsEditRoute, arguments: good);
|
.push(goodsEditRoute, arguments: good);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
|
import 'package:satu/core/models/inventarization/response/inventarization_response.dart';
|
||||||
|
import 'package:satu/core/services/dialog_service.dart';
|
||||||
|
import 'package:satu/views/inventarization/widget/good_inventarization_list_item.dart';
|
||||||
|
|
||||||
|
import '../../../core/entity/goods_entity.dart';
|
||||||
|
import '../../../core/models/inventarization/good_item/good_item.dart';
|
||||||
|
import '../../../core/services/dictionary_service.dart';
|
||||||
|
import '../../../core/services/inventarization_service.dart';
|
||||||
|
import '../../../core/services/navigator_service.dart';
|
||||||
|
import '../../../core/utils/locator.dart';
|
||||||
|
import '../../../routes/route_names.dart';
|
||||||
|
import '../../../shared/app_colors.dart';
|
||||||
|
import '../../../shared/shared_styles.dart';
|
||||||
|
import '../../../shared/ui_helpers.dart';
|
||||||
|
import '../../../widgets/bar/products_app_bar.dart';
|
||||||
|
|
||||||
|
class InventarizationEditView extends StatefulWidget {
|
||||||
|
const InventarizationEditView({
|
||||||
|
required this.item,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
final InventarizationResponse item;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InventarizationEditView> createState() =>
|
||||||
|
_InventarizationEditViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InventarizationEditViewState extends State<InventarizationEditView> {
|
||||||
|
final InventarizationService _service = locator<InventarizationService>();
|
||||||
|
final NavigatorService _navigatorService = locator<NavigatorService>();
|
||||||
|
final DialogService _dialogService = locator<DialogService>();
|
||||||
|
|
||||||
|
static const _pageSize = 20;
|
||||||
|
int _pageCurrent = 1;
|
||||||
|
bool _isLastPage = false;
|
||||||
|
|
||||||
|
final PagingController<int, GoodInventarization> _pagingController =
|
||||||
|
PagingController(firstPageKey: 1);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
|
_pageCurrent = pageKey;
|
||||||
|
_fetchData(pageKey, _pageSize);
|
||||||
|
});
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_pagingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: const ProductsAppBar(
|
||||||
|
title: 'Создание инвентаризации',
|
||||||
|
drawerShow: false,
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
verticalSpaceSmall,
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Text(
|
||||||
|
'Список товара',
|
||||||
|
style: textGray11Style,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(
|
||||||
|
'Количество',
|
||||||
|
style: textGray11Style,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
'Сумма',
|
||||||
|
style: textGray11Style,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
Expanded(
|
||||||
|
child: PagedListView<int, GoodInventarization>.separated(
|
||||||
|
//physics: const BouncingScrollPhysics(),
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return const Divider(
|
||||||
|
height: 1.0,
|
||||||
|
color: disableColor,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
pagingController: _pagingController,
|
||||||
|
builderDelegate: PagedChildBuilderDelegate<GoodInventarization>(
|
||||||
|
itemBuilder: (BuildContext context, GoodInventarization item,
|
||||||
|
int index) {
|
||||||
|
return GoodInventarizationListItem(
|
||||||
|
key: Key(
|
||||||
|
'good_inv_${item.id}',
|
||||||
|
),
|
||||||
|
inventoryId: widget.item.id,
|
||||||
|
inventoryItemId: item.id,
|
||||||
|
name: item.name,
|
||||||
|
categoryName: item.category,
|
||||||
|
count: item.cntBuh,
|
||||||
|
price: item.priceBuh,
|
||||||
|
ean: item.ean13,
|
||||||
|
isOdd: index % 2 == 0,
|
||||||
|
refresh: () {
|
||||||
|
_refreshData(_pageCurrent, _pageSize);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||||
|
floatingActionButton: floatingActionButtonRender(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// render floating buttons
|
||||||
|
Widget floatingActionButtonRender() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: <Widget>[
|
||||||
|
Visibility(
|
||||||
|
visible: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: FloatingActionButton(
|
||||||
|
mini: true,
|
||||||
|
elevation: 2,
|
||||||
|
backgroundColor: successColor,
|
||||||
|
onPressed: () {},
|
||||||
|
child: Icon(
|
||||||
|
Icons.check,
|
||||||
|
color: whiteColor,
|
||||||
|
size: 35,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
FloatingActionButton(
|
||||||
|
elevation: 2,
|
||||||
|
mini: true,
|
||||||
|
onPressed: () async {
|
||||||
|
final Good? good = await locator<NavigatorService>()
|
||||||
|
.push(addProductViewRoute) as Good?;
|
||||||
|
if (good != null) {
|
||||||
|
bool result =
|
||||||
|
await _service.addGoodToList(widget.item.id, good.id);
|
||||||
|
if (result) {
|
||||||
|
_pagingController.refresh();
|
||||||
|
} else {
|
||||||
|
_dialogService.showDialog(
|
||||||
|
description: 'Товара отсутсвует в остатке');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.add_rounded,
|
||||||
|
size: 40,
|
||||||
|
color: whiteColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
FloatingActionButton(
|
||||||
|
elevation: 2,
|
||||||
|
mini: true,
|
||||||
|
onPressed: () async {
|
||||||
|
final NavigatorService _nav = locator<NavigatorService>();
|
||||||
|
final dynamic result = await _nav.push(addByBarcodeViewRoute);
|
||||||
|
if (result != null) {
|
||||||
|
final List<Good> goods = await locator<DictionaryService>()
|
||||||
|
.getGoodsByNameOrEan(result as String);
|
||||||
|
if (goods.isNotEmpty) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Icon(Icons.qr_code_rounded, size: 30, color: whiteColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchData(int pageKey, int perPage) async {
|
||||||
|
final List<GoodInventarization> newItems =
|
||||||
|
await _service.getGoodByInventarizationId(
|
||||||
|
page: pageKey, perpage: perPage, id: widget.item.id);
|
||||||
|
_isLastPage = newItems.length < _pageSize;
|
||||||
|
_pageCurrent = pageKey;
|
||||||
|
if (_isLastPage) {
|
||||||
|
_pagingController.appendLastPage(newItems);
|
||||||
|
} else {
|
||||||
|
final nextPageKey = pageKey + 1;
|
||||||
|
_pageCurrent = nextPageKey;
|
||||||
|
_pagingController.appendPage(newItems, nextPageKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _refreshData(int pageKey, int perPage) async {
|
||||||
|
print('${pageKey} - ${perPage}');
|
||||||
|
final List<GoodInventarization> newItems =
|
||||||
|
await _service.getGoodByInventarizationId(
|
||||||
|
page: pageKey, perpage: perPage, id: widget.item.id);
|
||||||
|
final List<GoodInventarization> oldList = _pagingController.value.itemList ?? [];
|
||||||
|
oldList.setAll((pageKey - 1) * perPage , newItems);
|
||||||
|
setState(() {
|
||||||
|
_pagingController.itemList = oldList;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:satu/core/models/inventarization/inventarization_response.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:satu/core/models/inventarization/response/inventarization_response.dart';
|
||||||
import 'package:satu/core/services/inventarization_service.dart';
|
import 'package:satu/core/services/inventarization_service.dart';
|
||||||
|
import 'package:satu/core/services/navigator_service.dart';
|
||||||
import 'package:satu/core/utils/locator.dart';
|
import 'package:satu/core/utils/locator.dart';
|
||||||
import 'package:satu/shared/app_colors.dart';
|
import 'package:satu/shared/app_colors.dart';
|
||||||
import 'package:satu/shared/shared_styles.dart';
|
import 'package:satu/shared/shared_styles.dart';
|
||||||
import 'package:satu/shared/ui_helpers.dart';
|
import 'package:satu/shared/ui_helpers.dart';
|
||||||
import 'package:satu/views/inventarization/widget/inventarization_list_tile.dart';
|
import 'package:satu/views/inventarization/widget/inventarization_list_tile.dart';
|
||||||
|
|
||||||
|
import '../../../routes/route_names.dart';
|
||||||
import '../../../widgets/bar/products_app_bar.dart';
|
import '../../../widgets/bar/products_app_bar.dart';
|
||||||
|
import '../../dictionaries/component/dictionary_list_tile.dart';
|
||||||
|
|
||||||
class InventarizationView extends StatefulWidget {
|
class InventarizationView extends StatefulWidget {
|
||||||
const InventarizationView({Key? key}) : super(key: key);
|
const InventarizationView({Key? key}) : super(key: key);
|
||||||
|
|
@ -20,12 +24,15 @@ class InventarizationView extends StatefulWidget {
|
||||||
class _InventarizationViewState extends State<InventarizationView> {
|
class _InventarizationViewState extends State<InventarizationView> {
|
||||||
|
|
||||||
final InventarizationService _service = locator<InventarizationService>();
|
final InventarizationService _service = locator<InventarizationService>();
|
||||||
|
final NavigatorService _navigatorService = locator<NavigatorService>();
|
||||||
|
|
||||||
static const _pageSize = 20;
|
static const _pageSize = 20;
|
||||||
|
|
||||||
final PagingController<int, InventarizationResponse> _pagingController =
|
final PagingController<int, InventarizationResponse> _pagingController =
|
||||||
PagingController(firstPageKey: 1);
|
PagingController(firstPageKey: 1);
|
||||||
|
|
||||||
|
final DateFormat formatterDay = DateFormat('dd.MM.yyyy');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_pagingController.addPageRequestListener((pageKey) {
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
|
|
@ -89,16 +96,37 @@ class _InventarizationViewState extends State<InventarizationView> {
|
||||||
builderDelegate: PagedChildBuilderDelegate<InventarizationResponse>(
|
builderDelegate: PagedChildBuilderDelegate<InventarizationResponse>(
|
||||||
itemBuilder: (BuildContext context, InventarizationResponse item,
|
itemBuilder: (BuildContext context, InventarizationResponse item,
|
||||||
int index) {
|
int index) {
|
||||||
return InventarizationListTile(
|
return DictionaryTile(
|
||||||
key: Key('category_${item.id}'),
|
key: Key('category_${item.id}'),
|
||||||
// onPress: () async {
|
onPress: () async {
|
||||||
// final dynamic result = await _navigatorService
|
final dynamic result = await _navigatorService
|
||||||
// .push(categoryEditRoute, arguments: item);
|
.push(inventarizationEditRoute, arguments: item);
|
||||||
// if (result != null && true == (result as bool)) {
|
if (result != null && true == (result as bool)) {
|
||||||
// _pagingController.refresh();
|
_pagingController.refresh();
|
||||||
// }
|
}
|
||||||
// },
|
},
|
||||||
item: item,
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: InventarizationCellTile(
|
||||||
|
value: item.docNumber.toString()),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: InventarizationCellTile(
|
||||||
|
value: formatterDay.format(item.createdAt),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: InventarizationCellButton(
|
||||||
|
value: item.act,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:satu/core/models/dialog_models.dart';
|
||||||
|
import 'package:satu/core/redux/actions/sell_actions.dart';
|
||||||
|
import 'package:satu/core/redux/store.dart';
|
||||||
|
import 'package:satu/core/services/dialog_service.dart';
|
||||||
|
import 'package:satu/core/services/inventarization_service.dart';
|
||||||
|
import 'package:satu/core/utils/locator.dart';
|
||||||
|
import 'package:satu/core/utils/utils_parse.dart';
|
||||||
|
import 'package:satu/shared/app_colors.dart';
|
||||||
|
import 'package:satu/shared/shared_styles.dart';
|
||||||
|
import 'package:satu/views/work/views/add_by_barcode/add_by_barcode_view.dart';
|
||||||
|
import 'package:satu/widgets/ui/product_title_widget.dart';
|
||||||
|
|
||||||
|
class GoodInventarizationListItem extends StatefulWidget {
|
||||||
|
const GoodInventarizationListItem({
|
||||||
|
required Key key,
|
||||||
|
required this.price,
|
||||||
|
required this.count,
|
||||||
|
required this.inventoryItemId,
|
||||||
|
required this.inventoryId,
|
||||||
|
required this.refresh,
|
||||||
|
this.name = '',
|
||||||
|
this.ean,
|
||||||
|
this.categoryName,
|
||||||
|
this.isOdd = true,
|
||||||
|
this.transactionId,
|
||||||
|
|
||||||
|
}) : super(key: key);
|
||||||
|
final int inventoryItemId;
|
||||||
|
final int inventoryId;
|
||||||
|
final String name;
|
||||||
|
final String? ean;
|
||||||
|
final String? categoryName;
|
||||||
|
final double price;
|
||||||
|
final double count;
|
||||||
|
final bool isOdd;
|
||||||
|
final int? transactionId;
|
||||||
|
|
||||||
|
final void Function() refresh;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GoodInventarizationListItemState createState() =>
|
||||||
|
_GoodInventarizationListItemState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GoodInventarizationListItemState
|
||||||
|
extends State<GoodInventarizationListItem> {
|
||||||
|
final DialogService _dialogService = locator<DialogService>();
|
||||||
|
final InventarizationService _service = locator<InventarizationService>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Dismissible(
|
||||||
|
background: Container(
|
||||||
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
color: dangerColor,
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Удалить',
|
||||||
|
style: TextStyle(color: whiteColor, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
direction: DismissDirection.endToStart,
|
||||||
|
confirmDismiss: (DismissDirection direction) async {
|
||||||
|
final DialogResponse response =
|
||||||
|
await _dialogService.showConfirmationDialog(
|
||||||
|
title: 'Внимание',
|
||||||
|
description: 'Удалить из списка товар '
|
||||||
|
'"${widget.name}"'
|
||||||
|
' - ${widget.count} ед. ?',
|
||||||
|
confirmationTitle: 'Удалить',
|
||||||
|
cancelTitle: 'Отмена');
|
||||||
|
|
||||||
|
return response.confirmed;
|
||||||
|
},
|
||||||
|
onDismissed: (direction) {},
|
||||||
|
key: widget.key!,
|
||||||
|
child: ListTile(
|
||||||
|
key: widget.key!,
|
||||||
|
onTap: () {
|
||||||
|
editProductModal();
|
||||||
|
},
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0),
|
||||||
|
title: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: ProductTitleWidget(
|
||||||
|
name: widget.name,
|
||||||
|
ean: widget.ean,
|
||||||
|
categoryName: widget.categoryName,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Text(
|
||||||
|
formatDecimal(widget.count),
|
||||||
|
style: const TextStyle(fontSize: 12, color: textColor),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
formatDecimal(widget.price),
|
||||||
|
style: const TextStyle(fontSize: 12, color: textColor),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
tileColor: !widget.isOdd ? whiteColor : whiteColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> editProductModal() async {
|
||||||
|
final DialogResponse response =
|
||||||
|
await _dialogService.showConfirmationDialogInput(
|
||||||
|
title: widget.name,
|
||||||
|
requestCount: formatDecimal(widget.count),
|
||||||
|
);
|
||||||
|
if (response.confirmed) {
|
||||||
|
if (isNumeric(response.responseCount)) {
|
||||||
|
bool result = await _service.setCountToItem(widget.inventoryId, widget.inventoryItemId, double.parse(response.responseCount!));
|
||||||
|
if(result) {
|
||||||
|
widget.refresh();
|
||||||
|
} else {
|
||||||
|
_dialogService.showDialog(description: 'Что то пошло не так!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_dialogService.showDialog(description: 'Не верный формат');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,52 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:satu/core/models/inventarization/inventarization_response.dart';
|
import 'package:satu/core/models/inventarization/response/inventarization_response.dart';
|
||||||
import 'package:satu/shared/app_colors.dart';
|
import 'package:satu/shared/app_colors.dart';
|
||||||
|
|
||||||
class InventarizationListTile extends StatefulWidget {
|
|
||||||
const InventarizationListTile({required this.item, Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final InventarizationResponse item;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<InventarizationListTile> createState() =>
|
|
||||||
_InventarizationListTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _InventarizationListTileState extends State<InventarizationListTile> {
|
|
||||||
final DateFormat formatterDay = DateFormat('dd.MM.yyyy');
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(color: whiteColor),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: InventarizationCellTile(
|
|
||||||
value: widget.item.docNumber.toString()),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: InventarizationCellTile(
|
|
||||||
value: formatterDay.format(widget.item.createdAt),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 1,
|
|
||||||
child: InventarizationCellButton(
|
|
||||||
value: formatterDay.format(widget.item.createdAt),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InventarizationCellTile extends StatelessWidget {
|
class InventarizationCellTile extends StatelessWidget {
|
||||||
const InventarizationCellTile({
|
const InventarizationCellTile({
|
||||||
required this.value,
|
required this.value,
|
||||||
|
|
@ -58,7 +14,6 @@ class InventarizationCellTile extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.all(15.0),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
value,
|
value,
|
||||||
style: TextStyle(fontSize: 12),
|
style: TextStyle(fontSize: 12),
|
||||||
|
|
@ -73,20 +28,24 @@ class InventarizationCellButton extends StatelessWidget {
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String value;
|
final int? value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only( right: 15.0),
|
padding: const EdgeInsets.only( right: 15.0),
|
||||||
child: OutlinedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: value == null ? () {} : () {},
|
||||||
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'Акт',
|
'Акт',
|
||||||
style: TextStyle(fontSize: 12, color: whiteColor),
|
style: TextStyle(fontSize: 12, color: whiteColor),
|
||||||
),
|
),
|
||||||
style: OutlinedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: blueColor,
|
backgroundColor: value == null ? disableColor : blueColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ class _ProductListItemState extends State<ProductListItem> {
|
||||||
},
|
},
|
||||||
key: Key(widget.name),
|
key: Key(widget.name),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
//onTap: () => _onItemTapped(context),
|
key: Key(widget.name),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
editProductModal();
|
editProductModal();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ import 'package:satu/widgets/bar/products_header_bar.dart';
|
||||||
import 'package:satu/widgets/bar/products_title_bar.dart';
|
import 'package:satu/widgets/bar/products_title_bar.dart';
|
||||||
import 'package:satu/views/work/tabs/utils/product_utils.dart';
|
import 'package:satu/views/work/tabs/utils/product_utils.dart';
|
||||||
|
|
||||||
|
import '../../../core/entity/goods_entity.dart';
|
||||||
|
import '../../../core/redux/actions/sell_actions.dart';
|
||||||
|
import '../../../core/services/dictionary_service.dart';
|
||||||
import 'component/contagent_select_bar.dart';
|
import 'component/contagent_select_bar.dart';
|
||||||
|
|
||||||
class SellView extends StatelessWidget {
|
class SellView extends StatelessWidget {
|
||||||
|
|
@ -95,7 +98,7 @@ class SellView extends StatelessWidget {
|
||||||
converter: (Store<AppState> store) => store.state.sellState!,
|
converter: (Store<AppState> store) => store.state.sellState!,
|
||||||
builder: (_, SellState snapshot) {
|
builder: (_, SellState snapshot) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.all(15.w),
|
padding: EdgeInsets.all(15),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
|
@ -108,7 +111,7 @@ class SellView extends StatelessWidget {
|
||||||
backgroundColor: successColor,
|
backgroundColor: successColor,
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
locator<NavigatorService>().push(paymentViewRoute),
|
locator<NavigatorService>().push(paymentViewRoute),
|
||||||
child: Icon(Icons.check, color: whiteColor, size: 35.sp),
|
child: Icon(Icons.check, color: whiteColor, size: 35),
|
||||||
)),
|
)),
|
||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
|
@ -116,11 +119,16 @@ class SellView extends StatelessWidget {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
mini: true,
|
mini: true,
|
||||||
onPressed: () =>
|
onPressed: () async {
|
||||||
locator<NavigatorService>().push(addProductViewRoute),
|
final Good? good = await locator<NavigatorService>().push(addProductViewRoute) as Good?;
|
||||||
|
if(good !=null) {
|
||||||
|
Redux.store!.dispatch(addSellItem(good: good));
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add_rounded,
|
Icons.add_rounded,
|
||||||
size: 40.sp,
|
size: 40,
|
||||||
color: whiteColor,
|
color: whiteColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -134,17 +142,17 @@ class SellView extends StatelessWidget {
|
||||||
final dynamic result =
|
final dynamic result =
|
||||||
await _nav.push(addByBarcodeViewRoute);
|
await _nav.push(addByBarcodeViewRoute);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
// final List<Good> goods =
|
final List<Good> goods =
|
||||||
// await locator<DictionaryService>()
|
await locator<DictionaryService>()
|
||||||
// .getGoodsByEan(result as String);
|
.getGoodsByNameOrEan(result as String);
|
||||||
// if (goods.isNotEmpty) {
|
if (goods.isNotEmpty) {
|
||||||
// Redux.store
|
Redux.store
|
||||||
// ?.dispatch(addSellItem(good: goods.first));
|
?.dispatch(addSellItem(good: goods.first));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Icon(Icons.qr_code_rounded,
|
child: Icon(Icons.qr_code_rounded,
|
||||||
size: 30.sp, color: whiteColor),
|
size: 30, color: whiteColor),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ class AddByBarcodeView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddByBarcodeViewState extends State<AddByBarcodeView> {
|
class _AddByBarcodeViewState extends State<AddByBarcodeView> {
|
||||||
String _code = '';
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -30,11 +29,6 @@ class _AddByBarcodeViewState extends State<AddByBarcodeView> {
|
||||||
resultCallback: (String code) {
|
resultCallback: (String code) {
|
||||||
final NavigatorService _nav = locator<NavigatorService>();
|
final NavigatorService _nav = locator<NavigatorService>();
|
||||||
_nav.pop(code);
|
_nav.pop(code);
|
||||||
//Navigator.pop(context, code);
|
|
||||||
|
|
||||||
// setState(() {
|
|
||||||
// _code = code;
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:satu/core/entity/category_entity.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:satu/core/entity/goods_entity.dart';
|
import 'package:satu/core/entity/goods_entity.dart';
|
||||||
import 'package:satu/core/redux/actions/sell_actions.dart';
|
|
||||||
import 'package:satu/core/redux/store.dart';
|
|
||||||
import 'package:satu/core/services/dictionary_service.dart';
|
import 'package:satu/core/services/dictionary_service.dart';
|
||||||
import 'package:satu/core/services/navigator_service.dart';
|
import 'package:satu/core/services/navigator_service.dart';
|
||||||
import 'package:satu/core/utils/locator.dart';
|
import 'package:satu/core/utils/locator.dart';
|
||||||
import 'package:satu/shared/app_colors.dart';
|
import 'package:satu/shared/app_colors.dart';
|
||||||
import 'package:satu/shared/ui_helpers.dart';
|
import 'package:satu/shared/ui_helpers.dart';
|
||||||
import 'package:satu/views/work/views/add_product/component/add_category_list_item.dart';
|
|
||||||
import 'package:satu/widgets/bar/products_app_bar.dart';
|
import 'package:satu/widgets/bar/products_app_bar.dart';
|
||||||
import 'package:satu/widgets/bar/products_title_bar.dart';
|
import 'package:satu/widgets/bar/products_title_bar.dart';
|
||||||
import 'package:satu/widgets/fields/input_field.dart';
|
import 'package:satu/widgets/fields/input_field.dart';
|
||||||
|
|
||||||
|
import '../../../../core/models/dictionary/good/good_response_entity.dart';
|
||||||
import 'component/add_product_list_item.dart';
|
import 'component/add_product_list_item.dart';
|
||||||
|
|
||||||
class AddProductView extends StatefulWidget {
|
class AddProductView extends StatefulWidget {
|
||||||
|
|
@ -24,27 +24,30 @@ class _AddProductViewState extends State<AddProductView> {
|
||||||
final DictionaryService _dictionaryService = locator<DictionaryService>();
|
final DictionaryService _dictionaryService = locator<DictionaryService>();
|
||||||
final NavigatorService _navigatorService = locator<NavigatorService>();
|
final NavigatorService _navigatorService = locator<NavigatorService>();
|
||||||
late TextEditingController _searchTextController;
|
late TextEditingController _searchTextController;
|
||||||
final FocusNode _searchFocusNode = new FocusNode();
|
final FocusNode _searchFocusNode = FocusNode();
|
||||||
|
static const _pageSize = 20;
|
||||||
|
String query = '';
|
||||||
|
Timer? _debounce;
|
||||||
|
|
||||||
List<Category>? _history;
|
final PagingController<int, Good> _pagingController =
|
||||||
List<Category>? _categories;
|
PagingController(firstPageKey: 1);
|
||||||
List<Good>? _goods;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_searchTextController = TextEditingController();
|
_searchTextController = TextEditingController();
|
||||||
_searchTextController.addListener(() {
|
_searchTextController.addListener(() {
|
||||||
if (_searchTextController.text.isNotEmpty) {
|
setState(() {
|
||||||
searchByField(_searchTextController.text);
|
query = _searchTextController.text;
|
||||||
} else {
|
});
|
||||||
reset();
|
if (_debounce?.isActive ?? false) _debounce?.cancel();
|
||||||
}
|
_debounce = Timer(const Duration(milliseconds: 500), () {
|
||||||
|
_pagingController.refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
_pagingController.addPageRequestListener((pageKey) {
|
||||||
|
_fetchData(pageKey, _pageSize, query);
|
||||||
});
|
});
|
||||||
_history = [Category()..id = null];
|
|
||||||
_categories = [];
|
|
||||||
_goods = [];
|
|
||||||
super.initState();
|
super.initState();
|
||||||
navigateCategory(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -56,8 +59,7 @@ class _AddProductViewState extends State<AddProductView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
int catSize = _categories?.length ?? 0;
|
|
||||||
int goodSize = _goods?.length ?? 0;
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: ProductsAppBar(
|
appBar: ProductsAppBar(
|
||||||
title: 'Категория',
|
title: 'Категория',
|
||||||
|
|
@ -72,39 +74,33 @@ class _AddProductViewState extends State<AddProductView> {
|
||||||
),
|
),
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
ProductsTitleBarBar(
|
ProductsTitleBarBar(
|
||||||
title: goodSize > 0 ? 'Выберите товар' : 'Выберите категорию',
|
title: 'Выберите товар',
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.separated(
|
child: PagedListView<int, Good>.separated(
|
||||||
physics: BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
itemCount: catSize + goodSize,
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
if (index < catSize) {
|
|
||||||
Category category = _categories![index];
|
|
||||||
return AddCategoryListItem(
|
|
||||||
name: category.name,
|
|
||||||
key: Key('category_${category.id}'),
|
|
||||||
onPress: () => onCategoryPress(category),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Good good = _goods![index - catSize];
|
|
||||||
return AddProductListItem(
|
|
||||||
key: Key('product_${good.id}'),
|
|
||||||
ean: good.ean,
|
|
||||||
name: good.name,
|
|
||||||
price: good.price,
|
|
||||||
categoryName: _history?.last.name,
|
|
||||||
onPress: () {
|
|
||||||
onGoodPress(good);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (BuildContext context, int index) {
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
return Divider(
|
return const Divider(
|
||||||
height: 1.0,
|
height: 1.0,
|
||||||
color: disableColor,
|
color: disableColor,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
pagingController: _pagingController,
|
||||||
|
builderDelegate: PagedChildBuilderDelegate<Good>(
|
||||||
|
itemBuilder:
|
||||||
|
(BuildContext context, Good good, int index) {
|
||||||
|
return AddProductListItem(
|
||||||
|
key: Key('product_${good.id}'),
|
||||||
|
ean: good.ean,
|
||||||
|
name: good.name,
|
||||||
|
price: good.price,
|
||||||
|
categoryName: good.categoryName,
|
||||||
|
onPress: () {
|
||||||
|
onGoodPress(good);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -112,39 +108,29 @@ class _AddProductViewState extends State<AddProductView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCategoryPress(Category category) {
|
|
||||||
_history!.add(category);
|
|
||||||
navigateCategory(category.id!);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onGoodPress(Good good) {
|
void onGoodPress(Good good) {
|
||||||
Redux.store!.dispatch(addSellItem(good: good));
|
_navigatorService.pop<Good>(good);
|
||||||
_navigatorService.pop<String>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
_history = [Category()..id = 0];
|
|
||||||
navigateCategory(0);
|
|
||||||
_searchTextController.clear();
|
_searchTextController.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void navigateCategory(int? categoryId) async {
|
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
|
||||||
List<Category> categories =
|
final List<GoodResponseEntity> newItems = await _dictionaryService.getGoods(
|
||||||
await _dictionaryService.getCategoryByParentId(categoryId);
|
page: pageKey,
|
||||||
List<Good> goods =
|
filter: {'col': 'name', 'action': 'like', 'val': query ?? ''},
|
||||||
await _dictionaryService.getGoodsByCategoryId(categoryId);
|
perpage: perPage);
|
||||||
setState(() {
|
|
||||||
_categories = categories;
|
|
||||||
_goods = goods;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void searchByField(String query) async {
|
List<Good> items = newItems.map((e) => goodResponseToGood(e)).toList();
|
||||||
List<Category> categories = [];
|
final isLastPage = newItems.length < _pageSize;
|
||||||
List<Good> goods = await _dictionaryService.getGoodsByNameOrEan(query);
|
if (isLastPage) {
|
||||||
setState(() {
|
_pagingController.appendLastPage(items);
|
||||||
_categories = categories;
|
} else {
|
||||||
_goods = goods;
|
final nextPageKey = pageKey + 1;
|
||||||
});
|
_pagingController.appendPage(items, nextPageKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ class AddProductListItem extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Material(
|
return Material(
|
||||||
|
key: key,
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onPress!(),
|
onTap: () => onPress!(),
|
||||||
|
|
@ -51,7 +52,7 @@ class AddProductListItem extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
'$price ₸',
|
'$price ₸',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: ScreenUtil().setSp(20.0),
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -132,13 +132,16 @@ class _DialogManagerState extends State<DialogManager> {
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
const Divider(),
|
const Divider(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
InputFieldRounded(
|
Visibility(
|
||||||
controller: _controllerPrice,
|
visible: request.requestPrice != null,
|
||||||
placeholder: '',
|
child: InputFieldRounded(
|
||||||
suffixText: '₸',
|
controller: _controllerPrice,
|
||||||
labelText: 'Стоимость товара',
|
placeholder: '',
|
||||||
textInputType:
|
suffixText: '₸',
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
labelText: 'Стоимость товара',
|
||||||
|
textInputType:
|
||||||
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
InputFieldRounded(
|
InputFieldRounded(
|
||||||
textInputType:
|
textInputType:
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ class ProductTitleWidget extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
name,
|
name,
|
||||||
style: const TextStyle(fontSize: 14, color: textColor),
|
style: const TextStyle(fontSize: 12, color: textColor),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
if (ean != null)
|
if (ean != null)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue