null-safety-migration
suvaysov 2022-11-21 13:18:07 +06:00
parent 01d6e2d808
commit b5f9291116
40 changed files with 905 additions and 234 deletions

View File

@ -13,8 +13,11 @@ class BuyItemResponse {
required this.createdAt,
required this.updatedAt,
required this.unitPrice,
required this.name,
this.deletedAt,
this.refOkeiId,
this.ean13,
this.category
});
int id;
@ -34,6 +37,9 @@ class BuyItemResponse {
DateTime? deletedAt;
@JsonKey(name: 'unit_price')
double unitPrice;
String name;
String? ean13;
String? category;
factory BuyItemResponse.fromJson(Map<String, dynamic> json) => _$BuyItemResponseFromJson(json);

View File

@ -16,10 +16,13 @@ BuyItemResponse _$BuyItemResponseFromJson(Map<String, dynamic> json) =>
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
unitPrice: (json['unit_price'] as num).toDouble(),
name: json['name'] as String,
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
refOkeiId: json['ref_okei_id'] as int?,
ean13: json['ean13'] as String?,
category: json['category'] as String?,
);
Map<String, dynamic> _$BuyItemResponseToJson(BuyItemResponse instance) =>
@ -34,4 +37,7 @@ Map<String, dynamic> _$BuyItemResponseToJson(BuyItemResponse instance) =>
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'unit_price': instance.unitPrice,
'name': instance.name,
'ean13': instance.ean13,
'category': instance.category,
};

View File

@ -22,6 +22,7 @@ class BuyInvoiceResponse {
required this.eaccContragentId,
required this.createdAt,
required this.updatedAt,
required this.name,
this.deletedAt,
this.summ,
});
@ -43,6 +44,7 @@ class BuyInvoiceResponse {
DateTime updatedAt;
@JsonKey(name: 'deleted_at')
DateTime? deletedAt;
String name;
factory BuyInvoiceResponse.fromJson(Map<String, dynamic> json) => _$BuyInvoiceResponseFromJson(json);

View File

@ -16,6 +16,7 @@ BuyInvoiceResponse _$BuyInvoiceResponseFromJson(Map<String, dynamic> json) =>
eaccContragentId: json['eacc_contragent_id'] as int,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
name: json['name'] as String,
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
@ -34,4 +35,5 @@ Map<String, dynamic> _$BuyInvoiceResponseToJson(BuyInvoiceResponse instance) =>
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'name': instance.name,
};

View File

@ -0,0 +1,28 @@
import 'package:json_annotation/json_annotation.dart';
part 'stock_response.g.dart';
@JsonSerializable()
class StockResponse {
StockResponse({
required this.articul,
required this.ean13,
required this.eaccGoodId,
required this.name,
required this.price,
required this.cnt,
required this.katName,
});
int articul;
String ean13;
@JsonKey(name: 'eacc_good_id')
int eaccGoodId;
String name;
double price;
double cnt;
String katName;
factory StockResponse.fromJson(Map<String, dynamic> json) => _$StockResponseFromJson(json);
Map<String, dynamic> toJson() => _$StockResponseToJson(this);
}

View File

@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'stock_response.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
StockResponse _$StockResponseFromJson(Map<String, dynamic> json) =>
StockResponse(
articul: json['articul'] as int,
ean13: json['ean13'] as String,
eaccGoodId: json['eacc_good_id'] as int,
name: json['name'] as String,
price: (json['price'] as num).toDouble(),
cnt: (json['cnt'] as num).toDouble(),
katName: json['katName'] as String,
);
Map<String, dynamic> _$StockResponseToJson(StockResponse instance) =>
<String, dynamic>{
'articul': instance.articul,
'ean13': instance.ean13,
'eacc_good_id': instance.eaccGoodId,
'name': instance.name,
'price': instance.price,
'cnt': instance.cnt,
'katName': instance.katName,
};

View File

@ -2,6 +2,7 @@ import 'package:redux/redux.dart';
import 'package:meta/meta.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:satu/core/models/auth/auth_response.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/redux/state/user_state.dart';
import 'package:satu/core/services/api_service.dart';
import 'package:satu/core/services/dialog_service.dart';
@ -13,8 +14,8 @@ import '../store.dart';
@immutable
class SetUserStateAction {
SetUserStateAction(this.userState);
final UserState userState;
}
@ -47,6 +48,12 @@ ThunkAction<AppState> authenticate(String email, String password) {
};
}
ThunkAction<AppState> setDefaultContragent(ContragentResponseEntity? entity) {
return (Store<AppState> store) async {
store.dispatch(SetUserStateAction(UserState(defaultContragent: entity)));
};
}
ThunkAction<AppState> authenticateByToken(String token) {
return (Store<AppState> store) async {
store.dispatch(SetUserStateAction(UserState(isLoading: true)));

View File

@ -7,5 +7,6 @@ UserState userReducer(UserState prevState, SetUserStateAction action) {
isError: payload.isError,
isLoading: payload.isLoading,
auth: payload.auth,
defaultContragent: payload.defaultContragent,
);
}

View File

@ -1,43 +1,43 @@
import 'package:meta/meta.dart';
import 'package:satu/core/models/auth/auth_response.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
@immutable
class UserState {
factory UserState.initial(UserState? payload) => UserState(
isLoading: false,
isError: false,
auth: payload?.auth ?? (AuthResponse()..operation = false),
defaultContragent:
payload?.defaultContragent ?? ContragentResponseEntity(),
);
UserState({this.isError, this.isLoading, this.auth, this.defaultContragent});
UserState(
{this.isError,
this.isLoading,
this.auth,
});
final bool? isError;
final bool? isLoading;
final AuthResponse? auth;
final ContragentResponseEntity? defaultContragent;
UserState copyWith({
required bool? isError,
UserState copyWith(
{required bool? isError,
required bool? isLoading,
required AuthResponse? auth
}) {
required AuthResponse? auth,
required ContragentResponseEntity? defaultContragent}) {
return UserState(
isError: isError ?? this.isError,
isLoading: isLoading ?? this.isLoading,
auth: auth ?? this.auth,
);
defaultContragent: defaultContragent ?? this.defaultContragent);
}
static UserState? fromJson(dynamic json) {
return json != null
? UserState(
auth: AuthResponse.fromMap(json['auth']),
defaultContragent: json['defaultContragent'] == null
? null
: ContragentResponseEntity.fromJson(json['defaultContragent']),
)
: null;
}
@ -45,7 +45,8 @@ class UserState {
dynamic toJson() {
return {
'auth': auth != null ? auth!.toJson() : null,
'defaultContragent':
defaultContragent != null ? defaultContragent!.toJson() : null,
};
}
}

View File

@ -47,13 +47,6 @@ class ApiService extends BaseService {
final response = await http.post(Uri.https(host, url),
body: jsonEncode(requestBody), headers: headers);
if (requestBody != null) {
// log.i(host);
// log.i(url);
// log.i(headers);
//log.i(jsonEncode(requestBody));
//log.i(jsonEncode(response.body));
}
return response.body;
}
@ -143,6 +136,24 @@ class ApiService extends BaseService {
return result;
}
Future<ResponseOriginal> postRequestOriginal(String target,
{Map<String, dynamic>? requestBody}) async {
ResponseOriginal result;
try {
final Map<String, String> headers = <String, String>{
HttpHeaders.authorizationHeader: 'Bearer $token'
};
final String response =
await _post(target, header: headers, requestBody: requestBody);
result = ResponseOriginal.fromJson(json.decode(response));
} catch (e, stack) {
log.e('postRequest', e, stack);
result = ResponseOriginal()..message = e.toString();
}
return result;
}
Future<ResponseEntity> dictionarySave(
String target, Map<String, dynamic>? body) async {
ResponseEntity response;

View File

@ -1,5 +1,7 @@
import 'package:intl/intl.dart';
import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/models/but_item/buy_item_response.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/services/api_service.dart';
import 'package:satu/core/utils/locator.dart';
@ -15,6 +17,10 @@ class BuyService extends BaseService {
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'order' : {
'col': 'doc_number',
'desc': true
}
};
ResponseEntity categories = await _api.postRequest('/general_purchases_get',
@ -42,8 +48,6 @@ class BuyService extends BaseService {
'perpage': perpage,
'id': id
};
log.i(requestBody);
ResponseEntity categories = await _api.postRequest('/general_purchases_get_items',
requestBody: requestBody);
if (categories.original.items != null &&
@ -69,7 +73,6 @@ class BuyService extends BaseService {
'price': price,
'cnt': count
};
log.i(requestBody);
ResponseEntity response = await _api.postRequest('/general_purchases_edit_item',
requestBody: requestBody);
@ -86,7 +89,6 @@ class BuyService extends BaseService {
final Map<String, dynamic> requestBody = <String, dynamic>{
'id': id,
};
log.i(requestBody);
ResponseEntity response = await _api.postRequest('/general_purchases_delete_item',
requestBody: requestBody);
@ -105,7 +107,6 @@ class BuyService extends BaseService {
'eacc_good_id': goodId,
'id': invoiceId,
};
log.i(requestBody);
ResponseEntity response = await _api.postRequest('/general_purchases_add_item',
requestBody: requestBody);
@ -116,4 +117,40 @@ class BuyService extends BaseService {
}
return result;
}
Future<bool> confirmInvoice(int invoiceId) async {
bool result = false;
try {
final Map<String, dynamic> requestBody = <String, dynamic>{
'id': invoiceId,
};
ResponseEntity response = await _api.postRequest('/general_purchases_confirm',
requestBody: requestBody);
result = response.original.status == 'success';
log.i(response.toJson());
} catch (e, stack) {
log.e('getList', e, stack);
}
return result;
}
Future<bool> createBuy(ContragentResponseEntity contragent, DateTime date) async {
bool result = false;
try {
DateFormat formatter = DateFormat('yyyy-MM-dd');
final Map<String, dynamic> requestBody = <String, dynamic>{
'eacc_contragent_id': contragent.id,
'invoice_date': formatter.format(date),
};
log.i('requestBody', requestBody);
ResponseEntity response = await _api.postRequest('/general_purchases_add',
requestBody: requestBody);
log.i('response', response.toJson());
result = response.original.status == 'success';
} catch (e, stack) {
log.e('getList', e, stack);
}
return result;
}
}

View File

@ -30,8 +30,6 @@ class DictionaryService extends BaseService {
final ApiService _api = locator<ApiService>();
final DbService _db = locator<DbService>();
Category categoryResponseToCategory(CategoryResponse response) {
return Category()
..id = response.id
@ -84,7 +82,7 @@ class DictionaryService extends BaseService {
'val': categoryId
};
List<GoodResponseEntity> responses =
await getGoods(page: 1, perpage: 100, filter: filter);
await getGoods(page: 1, perpage: 100, filter: [filter]);
for (final GoodResponseEntity response in responses) {
final Good good = goodResponseToGood(response);
list.add(good);
@ -95,24 +93,38 @@ class DictionaryService extends BaseService {
return list;
}
Future<List<Good>> getGoodsByNameOrEan(String query) async {
Future<List<Good>> getGoodsByNameOrEan(String query, { bool onlyEan = false}) async {
final List<Good> list = [];
try {
final int? appCompanyId = Redux.store?.state.userState?.auth?.companyId;
String where =
'( $GoodColumnAppCompanyId = ? and $GoodColumnName like ? ) ';
final List args = [appCompanyId, '%$query%'];
if (_isNumericInt(query) && query.length >= 8) {
where += ' or $GoodColumnEan like ?';
args.add('${int.parse(query).toString()}%');
dynamic filter = [
{
'col': 'name',
'action': 'like',
'val': query,
},
{
'col': 'ean13',
'action': 'like',
'val': query,
}
final List<Map<String, dynamic>> elements =
await _db.queryRowsWithWhere(goodTableName, where, args);
for (final Map<String, dynamic> element in elements) {
list.add(Good.fromMap(element));
];
if (onlyEan) {
filter = [
{
'col': 'ean13',
'action': 'equals',
'val': query,
}
];
}
List<GoodResponseEntity> responses =
await getGoods(page: 1, perpage: 100, filter: filter);
for (final GoodResponseEntity response in responses) {
final Good good = goodResponseToGood(response);
list.add(good);
}
} catch (e, stack) {
log.e('getGoodsByCategoryId', e, stack);
log.e('getGoods', e, stack);
}
return list;
}
@ -172,13 +184,14 @@ class DictionaryService extends BaseService {
}
Future<List<GoodResponseEntity>> getGoods(
{required int page, required int perpage, dynamic filter}) async {
{required int page, required int perpage, dynamic filter,bool orGate = false}) async {
List<GoodResponseEntity> list = [];
try {
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'filter': [filter]
'filter': filter,
'or_gate': orGate
};
ResponseEntity categories =

View File

@ -12,10 +12,12 @@ import 'package:satu/core/models/flow/sell_return/sell_return_request.dart';
import 'package:satu/core/models/flow/transaction_state.dart';
import 'package:satu/core/redux/actions/sell_actions.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:uuid/uuid.dart';
import '../models/dictionary/contragent/contragent_response_entity.dart';
import 'api_service.dart';
import 'db_service.dart';
import 'dialog_service.dart';
@ -30,6 +32,7 @@ class SellService extends BaseService {
{double card = 0, double nal = 0, double total = 0}) async {
final SellRequest request = SellRequest();
final SellState sellState = Redux.store!.state.sellState!;
final UserState userState = Redux.store!.state.userState!;
final TransactionState transactionState = sellState.transactionState!;
final List<ProductDao> items = sellState.items!;
for (final ProductDao item in items) {
@ -40,10 +43,12 @@ class SellService extends BaseService {
request.invoiceId = transactionState.uuid;
request.section = transactionState.sectionName;
request.contragent = transactionState.contragentName;
ContragentResponseEntity? contragent = userState.defaultContragent;
final OperatorBean operator = OperatorBean()
..name = 'operator'
..code = 1;
request.operator = operator;
request.contragent = contragent?.name;
final SellResponse response = await _api.sell(request);
if (response.operation == false) {
_dialogService.showDialog(description: response.message);
@ -125,7 +130,6 @@ class SellService extends BaseService {
data.nal = nal;
data.total = total;
transaction.data = jsonEncode(data.toMap());
log.i(jsonEncode(data.toMap()));
await _db.update(transactionTableName, transaction.toMap());
return transaction.id;
}
@ -157,7 +161,6 @@ class SellService extends BaseService {
data.nal = nal;
data.total = total;
transaction.data = jsonEncode(data.toMap());
log.i(jsonEncode(data.toMap()));
return await _db.insert(transactionTableName, transaction.toMap());
}

View File

@ -0,0 +1,36 @@
import 'package:satu/core/base/base_service.dart';
import 'package:satu/core/models/stock/stock_response.dart';
import '../models/response/response_entity.dart';
import '../utils/locator.dart';
import 'api_service.dart';
class StockService extends BaseService {
final ApiService _api = locator<ApiService>();
Future<List<StockResponse>> getList(
{required int page, required int perpage, String? query}) async {
List<StockResponse> list = [];
try {
final Map<String, dynamic> requestBody = <String, dynamic>{
'page': page,
'perpage': perpage,
'search': query ?? ''
};
ResponseOriginal categories = await _api.postRequestOriginal('/get_stock_balance',
requestBody: requestBody);
if (categories.data != null &&
categories.data!.isNotEmpty) {
for (final dynamic map in categories.data!) {
final StockResponse item =
StockResponse.fromJson(map);
list.add(item);
}
}
} catch (e, stack) {
log.e('getList', e, stack);
}
return list;
}
}

View File

@ -10,6 +10,7 @@ import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/services/inventarization_service.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/services/stocks_service.dart';
import 'logger.dart';
@ -39,5 +40,7 @@ class LocatorInjector {
_log.d('Initializing InventarizationService Service');
locator.registerLazySingleton<InventarizationService>(
() => InventarizationService());
_log.d('Initializing StockService Service');
locator.registerLazySingleton<StockService>(() => StockService());
}
}

View File

@ -25,6 +25,7 @@ const String inventarizationEditRoute = 'inventarizationEditRoute';
//buy
const String buyEditRoute = 'buyEditRoute';
const String buyAddRoute = 'buyAddRoute';
// setting - ble printer
const String settingPrinterBluetoothViewRoute = 'SettingPrinterBluetoothView';

View File

@ -14,15 +14,16 @@ import 'package:satu/views/settings/printer_bluetooth/printer_encoding_select.da
import 'package:satu/views/settings/printer_bluetooth/printer_paper_size_select.dart';
import 'package:satu/views/settings/printer_bluetooth/printer_select.dart';
import 'package:satu/views/settings/printer_bluetooth/printer_view.dart';
import 'package:satu/views/work/tabs/buy/buy_add.dart';
import 'package:satu/views/work/tabs/buy/buy_edit.dart';
import 'package:satu/views/work/views/add_by_barcode/add_by_barcode_view.dart';
import 'package:satu/views/work/views/add_product/add_product_view.dart';
import 'package:satu/views/work/views/contragent/select_contragent_view.dart';
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/select_by_scan/add_by_barcode_view.dart';
import 'package:satu/views/work/work_view.dart';
import '../core/models/inventarization/response/inventarization_response.dart';
import '../views/work/views/select_contragent/select_contragent_view.dart';
import '../views/work/views/select_product/add_product_view.dart';
import './route_names.dart';
Route<dynamic> generateRoute(RouteSettings settings) {
@ -46,12 +47,12 @@ Route<dynamic> generateRoute(RouteSettings settings) {
case addProductViewRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: AddProductView(),
viewToShow: SelectProductView(),
);
case addByBarcodeViewRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: const AddByBarcodeView(),
viewToShow: const SelectByScanView(),
);
case settingPrinterBluetoothViewRoute:
return _getPageRoute(
@ -137,6 +138,11 @@ Route<dynamic> generateRoute(RouteSettings settings) {
invoice: invoice,
),
);
case buyAddRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: BuyAddView(),
);
default:
return MaterialPageRoute(

View File

@ -154,8 +154,8 @@ class _GoodsDictionaryViewState extends State<GoodsDictionaryView> {
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<GoodResponseEntity> newItems = await _dictionaryService.getGoods(
page: pageKey,
filter: {'col': 'name', 'action': 'like', 'val': query ?? ''},
perpage: perPage);
filter: [{'col': 'name', 'action': 'like', 'val': query ?? ''}],
perpage: perPage, orGate: true);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {

View File

@ -108,6 +108,14 @@ class _InventarizationEditViewState extends State<InventarizationEditView> {
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<GoodInventarization>(
noItemsFoundIndicatorBuilder: (BuildContext context) {
return const Center(
child: Text(
'Необходимо добавить товар',
style: textGray11Style,
),
);
},
itemBuilder: (BuildContext context, GoodInventarization item,
int index) {
return GoodInventarizationListItem(
@ -199,8 +207,25 @@ class _InventarizationEditViewState extends State<InventarizationEditView> {
final dynamic result = await _nav.push(addByBarcodeViewRoute);
if (result != null) {
final List<Good> goods = await locator<DictionaryService>()
.getGoodsByNameOrEan(result as String);
if (goods.isNotEmpty) {}
.getGoodsByNameOrEan(result as String, onlyEan: true);
if (goods.isNotEmpty) {
final Good good = goods.first;
bool result = await _service
.addGoodToList(widget.item.id, good.id);
if (result) {
_pagingController.refresh();
} else {
_dialogService.showDialog(
description:
'Товара отсутсвует в остатке или ранее не'
' использователся в системе',
);
}
} else {
_dialogService.showDialog(
description: 'Товар не найден',
);
}
}
},
child: Icon(Icons.qr_code_rounded, size: 30, color: whiteColor),

View File

@ -1,15 +1,11 @@
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 {

View File

@ -13,6 +13,7 @@ import 'package:satu/views/work/work_view.dart';
import 'package:satu/widgets/drawer/app_drawer.dart';
import '../dictionaries/contragents/contragents_view.dart';
import '../stocks/stocks_view.dart';
class MainView extends StatefulWidget {
@override
@ -30,6 +31,7 @@ class _MainViewState extends State<MainView> {
final _contragentDictView = ContragentsDictionaryView();
final _analyticsView = const AnalyticsView();
final _inventarizationView = InventarizationView();
final _stocksView = StocksView();
Widget _body(Type viewClass) {
if(viewClass == WorkView) {
@ -53,6 +55,9 @@ class _MainViewState extends State<MainView> {
if(viewClass == AnalyticsView) {
return _analyticsView;
}
if(viewClass == StocksView) {
return _stocksView;
}
return _workView;
}

View File

@ -0,0 +1,179 @@
import 'dart:async';
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/models/stock/stock_response.dart';
import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/core/services/stocks_service.dart';
import 'package:satu/views/inventarization/widget/good_inventarization_list_item.dart';
import 'package:satu/views/stocks/widget/stock_tile.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';
import '../../widgets/fields/input_field.dart';
class StocksView extends StatefulWidget {
const StocksView({
Key? key,
}) : super(key: key);
@override
State<StocksView> createState() => _StocksViewState();
}
class _StocksViewState extends State<StocksView> {
final StockService _service = locator<StockService>();
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = FocusNode();
String query = '';
Timer? _debounce;
static const _pageSize = 20;
bool _isLastPage = false;
final PagingController<int, StockResponse> _pagingController =
PagingController(firstPageKey: 1);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
setState(() {
query = _searchTextController.text;
});
if (_debounce?.isActive ?? false) _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
_pagingController.refresh();
});
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, query);
});
super.initState();
}
@override
void dispose() {
;
_debounce?.cancel();
_pagingController.dispose();
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const ProductsAppBar(
title: 'Остатки',
drawerShow: true,
),
body: Column(
children: [
InputField(
placeholder: 'Поиск по наименованию товара или штрих-код',
search: true,
controller: _searchTextController,
fieldFocusNode: _searchFocusNode,
),
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, StockResponse>.separated(
//physics: const BouncingScrollPhysics(),
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<StockResponse>(
noItemsFoundIndicatorBuilder: (BuildContext context) {
return const Center(
child: Text(
'В данном списке нет товаров',
style: textGray11Style,
),
);
},
itemBuilder:
(BuildContext context, StockResponse item, int index) {
return StockTile(
key: Key(
'good_stock_${item.eaccGoodId}',
),
name: item.name,
categoryName: item.katName,
count: item.cnt,
price: item.price,
ean: item.ean13,
);
},
),
),
),
],
),
);
}
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<StockResponse> newItems = await _service.getList(
page: pageKey,
perpage: perPage,
query: query,
);
_isLastPage = newItems.length < _pageSize;
if (_isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:satu/core/utils/utils_parse.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/widgets/ui/product_title_widget.dart';
class StockTile extends StatefulWidget {
const StockTile({
required Key key,
required this.price,
required this.count,
this.name = '',
this.ean,
this.categoryName,
}) : super(key: key);
final String name;
final String? ean;
final String? categoryName;
final double price;
final double count;
@override
_StockTileState createState() =>
_StockTileState();
}
class _StockTileState
extends State<StockTile> {
@override
Widget build(BuildContext context) {
return ListTile(
key: widget.key!,
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: whiteColor,
);
}
}

View File

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/widgets/fields/line_tile.dart';
import '../../../../core/services/buy_service.dart';
import '../../../../core/services/navigator_service.dart';
import '../../../../core/utils/locator.dart';
import '../../../../routes/route_names.dart';
import '../../../../widgets/bar/products_app_bar.dart';
import '../../../../widgets/buttons/busy_button.dart';
class BuyAddView extends StatefulWidget {
const BuyAddView({Key? key}) : super(key: key);
@override
State<BuyAddView> createState() => _BuyAddViewState();
}
class _BuyAddViewState extends State<BuyAddView> {
ContragentResponseEntity? _contragent;
DateTime _date = DateTime.now();
final BuyService _service = locator<BuyService>();
DateFormat _dateFormat = DateFormat('dd.MM.yyyy');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const ProductsAppBar(
title: 'Новая накладная покупки',
),
body: Column(
children: [
Expanded(
child: ListView(
children: [
LineTile(
key: const Key('BuyAddView_Contragent'),
_contragent?.name ?? 'Выберите контрагента',
onTap: () async {
ContragentResponseEntity? entity =
await locator<NavigatorService>()
.push(contragentSelectViewRoute)
as ContragentResponseEntity?;
if (entity != null) {
setState(() {
_contragent = entity;
});
}
},
labelText: 'Контрагент',
),
LineTile(
key: const Key('BuyAddView_Date'),
_dateFormat.format(_date),
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(), //get today's date
firstDate:DateTime(2000), //DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2101)
);
if (pickedDate != null) {
setState(() {
_date = pickedDate;
});
}
},
labelText: 'Дата накладной',
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 45, vertical: 30),
child: BusyButton(
title: 'СОЗДАТЬ',
busy: false,
onPressed: () async {
if (_contragent == null) {
return;
}
bool result = await _service.createBuy(_contragent!, _date);
if (result) {
locator<NavigatorService>().pop(result);
}
},
),
),
],
),
);
}
}

View File

@ -3,10 +3,11 @@ import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/models/but_item/buy_item_response.dart';
import 'package:satu/core/models/dialog_models.dart';
import 'package:satu/core/services/dialog_service.dart';
import 'package:satu/shared/shared_styles.dart';
import 'package:satu/views/work/tabs/buy/component/product_buy_tile.dart';
import '../../../../core/entity/goods_entity.dart';
import '../../../../core/models/buy_invoice/buy_invoice_response.dart';
import '../../../../core/services/buy_service.dart';
@ -38,6 +39,7 @@ class _BuyEditViewState extends State<BuyEditView> {
bool editable = false;
bool itemsExist = false;
@override
void initState() {
@ -55,7 +57,6 @@ class _BuyEditViewState extends State<BuyEditView> {
@override
void dispose() {
_pagingController.dispose();
super.dispose();
}
@ -79,15 +80,23 @@ class _BuyEditViewState extends State<BuyEditView> {
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<BuyItemResponse>(
itemBuilder: (BuildContext context, BuyItemResponse item,
int index) {
noItemsFoundIndicatorBuilder: (BuildContext context) {
return const Center(
child: Text(
'Необходимо добавить товар',
style: textGray11Style,
),
);
},
itemBuilder:
(BuildContext context, BuyItemResponse item, int index) {
return ProductBuyTile(
key: ValueKey(item.id),
ean: '1234567890123',
name: 'Картофель',
ean: item.ean13,
name: item.name,
price: item.price,
count: item.cnt,
categoryName: 'Овощи',
categoryName: item.category,
editable: editable,
invoiceId: widget.invoice.id,
id: item.id,
@ -115,14 +124,29 @@ class _BuyEditViewState extends State<BuyEditView> {
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Visibility(
visible: false,
visible: itemsExist,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
mini: true,
elevation: 2,
backgroundColor: successColor,
onPressed: () {},
onPressed: () async {
DialogResponse confirm =
await _dialogService.showConfirmationDialog(
title: 'Подтверждение',
description: 'Вы действительно хотите завершить покупку?',
confirmationTitle: 'Да',
cancelTitle: 'Нет',
);
if (confirm.confirmed) {
bool result =
await _service.confirmInvoice(widget.invoice.id);
if (result) {
locator<NavigatorService>().pop(result);
}
}
},
child: Icon(
Icons.check,
color: whiteColor,
@ -146,8 +170,7 @@ class _BuyEditViewState extends State<BuyEditView> {
_pagingController.refresh();
} else {
_dialogService.showDialog(
description:
'Товара отсутсвует в остатке или ранее не'
description: 'Товара отсутсвует в остатке или ранее не'
' использователся в системе',
);
}
@ -168,8 +191,25 @@ class _BuyEditViewState extends State<BuyEditView> {
final dynamic result = await _nav.push(addByBarcodeViewRoute);
if (result != null) {
final List<Good> goods = await locator<DictionaryService>()
.getGoodsByNameOrEan(result as String);
if (goods.isNotEmpty) {}
.getGoodsByNameOrEan(result as String, onlyEan: true);
if (goods.isNotEmpty) {
final Good good = goods.first;
bool result = await _service.addItem(
widget.invoice.id, good.id!);
if (result) {
_pagingController.refresh();
} else {
_dialogService.showDialog(
description: 'Товара отсутсвует в остатке или ранее не'
' использователся в системе',
);
}
} else {
_dialogService.showDialog(
description: 'Товара отсутсвует в остатке или ранее не'
' использователся в системе',
);
}
}
},
child: Icon(Icons.qr_code_rounded, size: 30, color: whiteColor),
@ -191,16 +231,21 @@ class _BuyEditViewState extends State<BuyEditView> {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
if ((_pagingController.value.itemList ?? []).isNotEmpty) {
setState(() {
itemsExist = true;
});
}
}
void _editData(int id, double price, double count) {
final List<BuyItemResponse> oldList =
_pagingController.value.itemList ?? [];
oldList..firstWhere((element) => element.id == id).price = price
oldList
..firstWhere((element) => element.id == id).price = price
..firstWhere((element) => element.id == id).cnt = count;
setState(() {
_pagingController.itemList = oldList;
});
}
}

View File

@ -21,8 +21,6 @@ class BuyView extends StatefulWidget {
}
class _BuyViewState extends State<BuyView> {
final BuyService _service = locator<BuyService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
@ -43,7 +41,6 @@ class _BuyViewState extends State<BuyView> {
@override
void dispose() {
_pagingController.dispose();
super.dispose();
}
@ -68,8 +65,8 @@ class _BuyViewState extends State<BuyView> {
},
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<BuyInvoiceResponse>(
itemBuilder: (BuildContext context, BuyInvoiceResponse item,
int index) {
itemBuilder:
(BuildContext context, BuyInvoiceResponse item, int index) {
return DictionaryTile(
key: Key('category_${item.id}'),
onPress: () async {
@ -88,24 +85,36 @@ class _BuyViewState extends State<BuyView> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${item.eaccContragentId.toString()}',
'${item.name}',
style: textBlack12Style,
),
SizedBox(
height: 5.0,
),
Text(
'Статус: ${item.refBuyInvoiceStatusId.toString()}',
'Номер: ${item.docNumber.toString()}',
style: textGray11Style,
),
],
)),
Expanded(
flex: 2,
child: Text(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${formatterDay.format(item.invoiceDate)}',
style: textBlack12Style,
),
SizedBox(
height: 5.0,
),
Text(
'Статус: ${item.refBuyInvoiceStatusId == 1 ? 'Новая' : 'Обработана'}',
style: textGray11Style,
),
],
),
),
Expanded(
flex: 1,
@ -127,12 +136,22 @@ class _BuyViewState extends State<BuyView> {
)
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final dynamic result = await _navigatorService.push(buyAddRoute);
if (result != null && true == (result as bool)) {
_pagingController.refresh();
}
},
mini: true,
child: const Icon(Icons.add),
),
);
}
Future<void> _fetchData(int pageKey, int perPage) async {
final List<BuyInvoiceResponse> newItems = await _service
.getList(page: pageKey, perpage: perPage);
final List<BuyInvoiceResponse> newItems =
await _service.getList(page: pageKey, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);

View File

@ -1,15 +1,10 @@
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/buy_service.dart';
import 'package:satu/core/services/dialog_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 ProductBuyTile extends StatefulWidget {

View File

@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:satu/core/models/dictionary/contragent/contragent_response_entity.dart';
import 'package:satu/core/redux/actions/user_actions.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/routes/route_names.dart';
import 'package:satu/shared/app_colors.dart';
class ContragentSelectBar extends StatelessWidget {
const ContragentSelectBar({required this.value, Key? key}) : super(key: key);
final String value;
@ -17,8 +19,13 @@ class ContragentSelectBar extends StatelessWidget {
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {
locator<NavigatorService>().push(contragentSelectViewRoute);
onTap: () async {
ContragentResponseEntity? entity =
await locator<NavigatorService>()
.push(contragentSelectViewRoute) as ContragentResponseEntity?;
if (entity != null) {
Redux.store?.dispatch(setDefaultContragent(entity));
}
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 08.w, horizontal: 15.w),

View File

@ -9,9 +9,10 @@ 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';
import '../../../views/select_by_scan/add_by_barcode_view.dart';
class ProductSellTile extends StatefulWidget {
const ProductSellTile(
@ -42,7 +43,7 @@ class _ProductSellTileState extends State<ProductSellTile> {
void _onItemTapped(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => const AddByBarcodeView()));
builder: (BuildContext context) => const SelectByScanView()));
}
@override

View File

@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:redux/src/store.dart';
import 'package:satu/core/models/flow/dao/product_dao.dart';
import 'package:satu/core/redux/state/sell_state.dart';
import 'package:satu/core/redux/state/user_state.dart';
import 'package:satu/core/redux/store.dart';
import 'package:satu/core/services/navigator_service.dart';
import 'package:satu/core/utils/locator.dart';
@ -40,9 +41,14 @@ class SellView extends StatelessWidget {
),
body: Column(
children: [
const ContragentSelectBar(
value: 'Частное лицо',
),
StoreConnector<AppState, UserState>(
converter: (store) => store.state.userState!,
builder: (_, uState) {
return ContragentSelectBar(
value: (uState.defaultContragent?.name ??
'Выберите контрагента'),
);
}),
Expanded(
child: ListView(
physics: const BouncingScrollPhysics(),
@ -120,11 +126,11 @@ class SellView extends StatelessWidget {
elevation: 2,
mini: true,
onPressed: () async {
final Good? good = await locator<NavigatorService>().push(addProductViewRoute) as Good?;
final Good? good = await locator<NavigatorService>()
.push(addProductViewRoute) as Good?;
if (good != null) {
Redux.store!.dispatch(addSellItem(good: good));
}
},
child: Icon(
Icons.add_rounded,
@ -144,7 +150,7 @@ class SellView extends StatelessWidget {
if (result != null) {
final List<Good> goods =
await locator<DictionaryService>()
.getGoodsByNameOrEan(result as String);
.getGoodsByNameOrEan(result as String, onlyEan: true);
if (goods.isNotEmpty) {
Redux.store
?.dispatch(addSellItem(good: goods.first));

View File

@ -1,100 +0,0 @@
import 'package:flutter/material.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/widgets/fields/input_field.dart';
import 'companent/contragent_list_item.dart';
class SelectContragentView extends StatefulWidget {
@override
_SelectContragentViewState createState() => _SelectContragentViewState();
}
class _SelectContragentViewState extends State<SelectContragentView> {
final DictionaryService _dictionaryService = locator<DictionaryService>();
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = new FocusNode();
final List<Category> _contragents = [];
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
searchByField(_searchTextController.text);
} else {
reset();
}
});
super.initState();
}
@override
void dispose() {
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const ProductsAppBar(
title: 'Контрагент',
),
body: Column(
children: [
InputField(
placeholder: 'Поиск по наименованию или коду товара',
search: true,
controller: _searchTextController,
fieldFocusNode: _searchFocusNode,
),
verticalSpaceTiny,
const ProductsTitleBarBar(
title: 'Выберите контрагента',
),
Expanded(
child: ListView.separated(
physics: const BouncingScrollPhysics(),
itemCount: _contragents.length,
itemBuilder: (BuildContext context, int index) {
final Category category = _contragents[index];
return ContragentListItem(
name: category.name,
key: Key('category_${category.id}'),
onPress: () => () {},
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider(
height: 1.0,
color: disableColor,
);
},
),
),
],
),
);
}
void reset() {
_searchTextController.clear();
}
void searchByField(String query) async {
List<Good> goods = await _dictionaryService.getGoodsByNameOrEan(query);
setState(() {
goods;
});
}
}

View File

@ -5,17 +5,17 @@ import 'package:satu/core/utils/locator.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/tools/app_barcode_scanner_widget.dart';
class AddByBarcodeView extends StatefulWidget {
class SelectByScanView extends StatefulWidget {
const AddByBarcodeView({
const SelectByScanView({
Key? key
}) : super(key: key);
@override
_AddByBarcodeViewState createState() => _AddByBarcodeViewState();
_SelectByScanViewState createState() => _SelectByScanViewState();
}
class _AddByBarcodeViewState extends State<AddByBarcodeView> {
class _SelectByScanViewState extends State<SelectByScanView> {
@override
Widget build(BuildContext context) {
return Scaffold(

View File

@ -0,0 +1,126 @@
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:satu/core/entity/category_entity.dart';
import 'package:satu/core/entity/goods_entity.dart';
import 'package:satu/core/services/dictionary_service.dart';
import 'package:satu/core/utils/locator.dart';
import 'package:satu/shared/app_colors.dart';
import 'package:satu/shared/ui_helpers.dart';
import 'package:satu/widgets/bar/products_app_bar.dart';
import 'package:satu/widgets/bar/products_title_bar.dart';
import 'package:satu/widgets/fields/input_field.dart';
import '../../../../core/models/dictionary/contragent/contragent_response_entity.dart';
import '../../../../core/services/navigator_service.dart';
import '../../../dictionaries/component/dictionary_list_tile.dart';
import 'companent/contragent_list_item.dart';
class SelectContragentView extends StatefulWidget {
@override
_SelectContragentViewState createState() => _SelectContragentViewState();
}
class _SelectContragentViewState extends State<SelectContragentView> {
final DictionaryService _dictionaryService = locator<DictionaryService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
late TextEditingController _searchTextController;
final FocusNode _searchFocusNode = FocusNode();
late List<ContragentResponseEntity> items = [];
static const _pageSize = 20;
final PagingController<int, ContragentResponseEntity> _pagingController =
PagingController(firstPageKey: 0);
@override
void initState() {
_searchTextController = TextEditingController();
_searchTextController.addListener(() {
if (_searchTextController.text.isNotEmpty) {
//searchByField(_searchTextController.text);
} else {
reset();
}
});
_pagingController.addPageRequestListener((pageKey) {
_fetchData(pageKey, _pageSize, null);
});
super.initState();
}
Future<void> initQuery() async {
//searchByField('');
}
@override
void dispose() {
_searchTextController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ProductsAppBar(
title: 'Контрагенты',
),
body: Column(
children: [
InputField(
placeholder: 'Поиск по наименованию',
search: true,
controller: _searchTextController,
fieldFocusNode: _searchFocusNode,
),
const ProductsTitleBarBar(title: 'Список контрагентов'),
Expanded(
child: PagedListView<int, ContragentResponseEntity>(
pagingController: _pagingController,
builderDelegate:
PagedChildBuilderDelegate<ContragentResponseEntity>(
itemBuilder: (BuildContext context,
ContragentResponseEntity entity, int index) {
return DictionaryTile(
key: Key('contragent_${entity.id}'),
onPress: () async {
_navigatorService.pop(entity);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
entity.name ?? '',
style: const TextStyle(fontSize: 12, color: textColor),
),
Text('БИН/ИИН: ${entity.biniin}',
style: const TextStyle(
fontSize: 10, color: placeholderColor)),
],
),
);
},
),
))
],
),
);
}
void reset() {
_searchTextController.clear();
}
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<ContragentResponseEntity> newItems = await _dictionaryService
.getContragents(page: pageKey, query: query, perpage: perPage);
final isLastPage = newItems.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + newItems.length;
_pagingController.appendPage(newItems, nextPageKey);
}
}
}

View File

@ -15,12 +15,12 @@ import 'package:satu/widgets/fields/input_field.dart';
import '../../../../core/models/dictionary/good/good_response_entity.dart';
import 'component/add_product_list_item.dart';
class AddProductView extends StatefulWidget {
class SelectProductView extends StatefulWidget {
@override
_AddProductViewState createState() => _AddProductViewState();
_SelectProductViewState createState() => _SelectProductViewState();
}
class _AddProductViewState extends State<AddProductView> {
class _SelectProductViewState extends State<SelectProductView> {
final DictionaryService _dictionaryService = locator<DictionaryService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
late TextEditingController _searchTextController;
@ -121,8 +121,12 @@ class _AddProductViewState extends State<AddProductView> {
Future<void> _fetchData(int pageKey, int perPage, String? query) async {
final List<GoodResponseEntity> newItems = await _dictionaryService.getGoods(
page: pageKey,
filter: {'col': 'name', 'action': 'like', 'val': query ?? ''},
perpage: perPage);
filter: [{'col': 'name', 'action': 'like', 'val': query ?? ''}, {
'col': 'ean13',
'action': 'like',
'val': query ?? ''
}],
perpage: perPage, orGate: true);
List<Good> items = newItems.map((e) => goodResponseToGood(e)).toList();
final isLastPage = newItems.length < _pageSize;

View File

@ -14,6 +14,7 @@ import 'package:satu/views/dictionaries/category/category_view.dart';
import 'package:satu/views/dictionaries/contragents/contragents_view.dart';
import 'package:satu/views/dictionaries/goods/goods_view.dart';
import 'package:satu/views/settings/setting_view.dart';
import 'package:satu/views/stocks/stocks_view.dart';
import 'package:satu/views/work/work_view.dart';
import '../../views/inventarization/view/inventarization_view.dart';
@ -50,9 +51,8 @@ class AppDrawer extends StatelessWidget {
text: 'Остатки',
onTap: () {
Navigator.of(context).pop();
Redux.store!.dispatch(navigateDrawer(AnalyticsView));
},
disable: true,
Redux.store!.dispatch(navigateDrawer(StocksView));
}
),
_createDrawerItem(
svgFile: 'inventarization',

View File

@ -6,7 +6,7 @@ import 'note_text.dart';
class LineTile extends StatelessWidget {
const LineTile(this.text,
{required this.onTap, this.labelText, this.placeholder = 'Выберите'});
{required this.onTap, this.labelText, this.placeholder = 'Выберите', Key? key}) : super(key: key);
final String text;
final String placeholder;

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
version: 1.0.1+2
environment: