aman-kassa-flutter/lib/views/payment_nfc/payment_nfc_view.dart

575 lines
18 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:convert';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/logger.dart';
import 'package:aman_kassa_flutter/core/models/aman_dao.dart';
import 'package:aman_kassa_flutter/core/models/calc_model.dart';
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/check_data.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/halyk_post_session.dart';
import 'package:aman_kassa_flutter/core/models/product_dao.dart';
import 'package:aman_kassa_flutter/core/models/response.dart';
import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/calc_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/operation_const.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
import 'package:aman_kassa_flutter/redux/state/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart';
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/views/check/image_show_container.dart';
import 'package:aman_kassa_flutter/views/payment/payment_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/action_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/background_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/card_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/logo_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/phone_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/widgets/text_state.dart';
import 'package:aman_kassa_flutter/widgets/components/calculator/calculator.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:logger/logger.dart';
class PaymentNfcView extends StatefulWidget {
final PaymentModel model;
const PaymentNfcView({Key key, this.model}) : super(key: key);
@override
_PaymentNfcViewState createState() => _PaymentNfcViewState();
}
class _PaymentNfcViewState extends State<PaymentNfcView> {
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
BankService _bankService = locator<BankService>();
DialogService _dialogService = locator<DialogService>();
final DataService _dataService = locator<DataService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
Logger log = getLogger('PaymentNfcView');
bool isBusy;
bool isPhoneScaled;
int status;
@override
void initState() {
super.initState();
isBusy = false;
isPhoneScaled = false;
status = 0;
start();
}
void start() async {
//Авторизация
String token = Redux.store.state.userState.user.token;
BankState bankState = Redux.store.state.bankState;
//права доступа
HalykPosSession session = await _bankService.renewToken(token: token, login: bankState.login, password: bankState.password);
log.i(session);
if ('1' == '1') {
setState(() {
status = 4;
});
return;
}
//права доступа
bool success = await _bankService.permissions();
log.i(success);
if (!success) {
setState(() {
status = 4;
});
return;
}
var today = new DateTime.now();
var yesterday = today.subtract(new Duration(days: 1));
if( Redux.store.state.userState == null
|| Redux.store.state.userState.smena == null
|| Redux.store.state.userState.smena.startedAt == null
|| yesterday.isAfter(Redux.store.state.userState.smena.startedAt)) {
_dialogService.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
_navigatorService.pop();
return;
}
//Инициализация
bool initialized = await _bankService.init();
log.i(initialized);
if (!initialized) {
setState(() {
status = 4;
});
return;
}
//Проверка связи
bool connected = await _bankService.connect();
log.i(connected);
if (!connected) {
setState(() {
status = 5;
});
return;
}
AmanDao authDao = await _bankService.auth(
login: bankState.login, password: bankState.password);
if (!authDao.success) {
setState(() {
status = 6;
});
if (authDao.msg != null) {
log.i(authDao.msg);
_dialogService.showDialog(description: authDao.msg);
}
return;
}
//валюта
bool currency = await _bankService.currency();
log.i(currency);
if (!currency) {
setState(() {
status = 4;
});
return;
}
if(widget.model.voucher == null) {
pay();
} else {
refund();
}
}
refund() async {
CardData _cardData = widget.model.cardData;
AmanDao findTransaction = await _bankService.findTransaction(transactionNumber: _cardData.transactionNumber, authorizationCode: _cardData.authorizationCode);
if(!findTransaction.success){
_dialogService.showDialog(description: findTransaction.msg);
setState(() {
status = 8;
});
return;
}
setState(() {
status = 1;
isPhoneScaled = true;
});
AmanDao refundDao = await _bankService.refund();
if (!refundDao.success) {
int _status = 7;
setState(() {
status = _status;
isPhoneScaled = false;
});
if (refundDao.msg != null) {
log.i(refundDao.msg);
_dialogService.showDialog(description: refundDao.msg);
}
return;
}
setState(() {
status = 9;
isPhoneScaled = false;
});
//check
pressRefund('card' , refundDao.data);
}
pay() async {
//Платеж
num total = 0.0;
if (widget.model.mode == SettingModeCalc) {
total = totalCalc(Redux.store.state.calcState.calcItems);
} else {
total = totalKassa(Redux.store.state.kassaState.kassaItems);
}
setState(() {
status = 1;
isPhoneScaled = true;
});
log.i('total: $total');
AmanDao payDao = await _bankService.pay(amount: total);
if (!payDao.success) {
int _status = 7;
if (payDao.data != null ) {
if("onWrongApiCalled" == payDao.data.toString()) {
cancel();
} else if("notAuthorized" == payDao.data.toString() ) {
cancel();
_status = 6;
}
}
setState(() {
status = _status;
isPhoneScaled = false;
});
if (payDao.msg != null) {
log.i(payDao.msg);
_dialogService.showDialog(description: payDao.msg);
}
return;
}
setState(() {
status = 3;
isPhoneScaled = false;
});
//check
pressPayment('card' , payDao.data);
}
cancel() async {
bool isCanceled = await _bankService.cancel();
_navigatorService.pop();
}
pressPayment(String type, dynamic cardDataDynamic) async {
setState(() {
isBusy = true;
});
Dialogs.showLoadingDialog(context, _keyLoader);
try {
AppState _state = Redux.store.state;
String _token = _state.userState.user.token;
String _tradeType = _state.settingState.tradeType;
String _mode = _state.settingState.mode;
if (_mode == SettingModeCalc) {
_tradeType = SettingTradeTypeGood;
}
CardData cardData = cardDataDynamic != null ? CardData.fromJson(cardDataDynamic) : null;
List<ProductDao> kassaItems = _state.kassaState.kassaItems;
List<CalcModel> calcItems = _state.calcState.calcItems;
Response<dynamic> response = await _dataService.sellOrReturn(
token: _token,
kassaItems: kassaItems,
paymentType: type,
operationType: widget.model.operationType,
tradeType: _tradeType,
calcItems: calcItems,
mode: _mode,
cardData: cardData
);
setState(() {
isBusy = false;
});
if (response != null) {
if (response.operation) {
String message = response.body['message'];
String check = response.body['check'];
var checkText = response.body['check_text'];
String url = response?.body['link'];
print('url : $url');
if (_mode == SettingModeCalc) {
Redux.store.dispatch(cleanCalcItems);
} else if (_mode == SettingModeKassa) {
Redux.store.dispatch(cleanKassaItems);
}
Redux.store.dispatch(checkMoney);
Redux.store.dispatch(openSmenaPseudo);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_navigatorService.replace(HomeViewRoute);
_navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(data: new CheckImageModal(base64Data: check, textData: checkText !=null ? jsonEncode(checkText) : null ), title: message, url: url));
} else if (!response.operation &&
![401, 402, 403, 412, 500].contains(response.status)) {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']);
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} catch (e) {
print(e);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} finally {
//Navigator.of(context, rootNavigator: true).pop();
setState(() {
isBusy = false;
});
}
}
pressRefund(String type, dynamic cardDataDynamic) async {
setState(() {
isBusy = true;
});
Dialogs.showLoadingDialog(context, _keyLoader);
try {
AppState _state = Redux.store.state;
String _token = _state.userState.user.token;
CardData _cardData = cardDataDynamic != null ? CardData.fromJson(cardDataDynamic) : null;
CheckData _checkData = CheckData.fromJson(json.decode(widget.model.voucher.data));
Response<dynamic> response = await _dataService.refundM4Bank(
token: _token,
cardData: _cardData,
checkData: _checkData
);
setState(() {
isBusy = false;
});
if (response != null) {
if (response.operation) {
String message = response.body['message'];
String check = response.body['check'];
var checkText = response.body['check_text'];
String url = response?.body['link'];
print('url : $url');
Redux.store.dispatch(checkMoney);
Redux.store.dispatch(openSmenaPseudo);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_navigatorService.replace(HomeViewRoute);
_navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(data: new CheckImageModal(base64Data: check, textData: checkText !=null ? jsonEncode(checkText) : null ), title: message, url: url));
} else if (!response.operation &&
![401, 402, 403, 412, 500].contains(response.status)) {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']);
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} catch (e) {
print(e);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} finally {
//Navigator.of(context, rootNavigator: true).pop();
setState(() {
isBusy = false;
});
}
}
@override
void dispose() {
_bankService.shutdown();
super.dispose();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
if (!isBusy) Navigator.pop(context);
return new Future(() => false);
},
child: Scaffold(
appBar: AppBar(
brightness: Brightness.light,
backgroundColor: purpleColor,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: whiteColor,
onPressed: () => Navigator.pop(context),
),
title: Text(
dataTitle(),
style: TextStyle(color: whiteColor),
),
),
body: Container(
decoration: BoxDecoration(color: purpleColor),
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setSp(12.0),
horizontal: ScreenUtil().setSp(12.0)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
dataText(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: whiteColor.withOpacity(0.7),
fontSize: ScreenUtil().setSp(15.0)),
),
buildStoreConnector(),
Expanded(
child: Stack(
children: <Widget>[
BackgroundView(),
LogoView(),
TextStateView(
status: status,
),
CardView(
show: isPhoneScaled,
),
PhoneView(
scaled: isPhoneScaled,
status: status,
),
buildActionView()
],
),
)
],
),
),
),
);
}
ActionView buildActionView() {
switch (status) {
case 5:
return ActionView(
show: true,
acceptText: 'Повторить',
acceptCallback: () async {
await _bankService.shutdown();
start();
},
declineText: 'Отмена',
declineCallback: () {
cancel();
},
);
break;
case 6:
return ActionView(
show: true,
acceptText: 'Повторить',
acceptCallback: () async {
await _bankService.shutdown();
start();
},
declineText: 'Отмена',
declineCallback: () {
cancel();
},
);
break;
case 7:
return ActionView(
show: true,
acceptText: 'Повторить',
acceptCallback: () {
pay();
},
declineText: 'Отмена',
declineCallback: () {
cancel();
},
);
break;
case 8:
return ActionView(
show: true,
acceptText: 'Повторить',
acceptCallback: () {
refund();
},
declineText: 'Отмена',
declineCallback: () {
cancel();
},
);
break;
default:
}
return ActionView();
}
String dataTitle() =>
widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат';
String dataText() => widget.model.operationType == OperationTypePay
? 'К оплате'
: 'К возврату';
StoreConnector buildStoreConnector() {
if (widget.model.mode == SettingModeCalc) {
return StoreConnector<AppState, CalcState>(
converter: (store) => store.state.calcState,
builder: (_, vm) {
return Text('${totalCalc(vm.calcItems)} тнг',
style: TextStyle(
fontWeight: FontWeight.bold,
color: whiteColor,
fontSize: 35));
});
}
if(widget.model.voucher !=null) {
return StoreConnector<AppState, KassaState>(
converter: (store) => store.state.kassaState,
builder: (_, vm) {
return Text('${widget.model.voucher.total} тнг',
style: TextStyle(
fontWeight: FontWeight.bold,
color: whiteColor,
fontSize: 35));
});
}
return StoreConnector<AppState, KassaState>(
converter: (store) => store.state.kassaState,
builder: (_, vm) {
return Text('${totalKassa(vm.kassaItems)} тнг',
style: TextStyle(
fontWeight: FontWeight.bold,
color: whiteColor,
fontSize: 35));
});
}
num totalKassa(List<ProductDao> kassaItems) {
num total = 0.0;
kassaItems.forEach((element) {
total += element.total == null ? 0.0 : element.total.toDouble();
});
return total;
}
num totalCalc(List<CalcModel> items) {
num total = 0.0;
items.forEach((element) {
if (element.operation == Calculations.MULTIPLY) {
double num1 = element.num1 == null ? 0.0 : double.parse(element.num1);
double num2 = element.num2 == null ? 0.0 : double.parse(element.num2);
total += num1 * num2;
} else {
total += element.num1 == null ? 0.0 : double.parse(element.num1);
}
});
return total;
}
}