aman-kassa-flutter/lib/views/payment/payment_view.dart

446 lines
16 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/models/calc_model.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/card_data.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/ForteService.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/setting_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/shared/ui_helpers.dart';
import 'package:aman_kassa_flutter/views/check/image_show_container.dart';
import 'package:aman_kassa_flutter/widgets/components/calculator/calculator.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:aman_kassa_flutter/widgets/fields/input_field.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import '../../core/models/aman_dao.dart';
import '../../core/models/card_data.dart';
import '../../core/models/card_data.dart';
import 'forte_pos_service.dart';
class PaymentView extends StatefulWidget {
final PaymentModel model;
const PaymentView({Key? key, required this.model}) : super(key: key);
@override
_PaymentViewState createState() => _PaymentViewState();
}
class _PaymentViewState extends State<PaymentView> {
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final DataService _dataService = locator<DataService>();
final DialogService _dialogService = locator<DialogService>();
dynamic _bankService;
final NavigatorService _navigatorService = locator<NavigatorService>();
final TextEditingController _iinController = new TextEditingController();
late bool isBusy;
late bool isBankApiAccess;
var height = AppBar().preferredSize.height;
@override
void initState() {
super.initState();
isBusy = false;
isBankApiAccess = false;
_bankInit();
}
@override
void dispose() {
_iinController.dispose();
super.dispose();
}
_bankInit() async {
BankState? state = Redux.store?.state.bankState;
print(state?.toJson());
if (state?.sessionType == 'Halyk' && state?.session != null) {
_bankService = locator<BankService>();
} else if (state?.sessionType == 'Forte' && state?.session != null) {
_bankService = locator<ForteService>();
} else {
setState(() {
isBankApiAccess = false;
});
return;
}
int version = await _bankService.version();
setState(() {
isBankApiAccess = version >= _bankService.sdkVersion;
});
}
@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: whiteColor,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.black87,
onPressed: () => Navigator.pop(context),
),
title: Text(
dataTitle(),
style: TextStyle(color: Colors.black87),
),
),
body: SingleChildScrollView(
child: SizedBox(
height: ScreenUtil().screenHeight - ScreenUtil().statusBarHeight - height,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
dataText(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black26,
fontSize: 15),
),
buildStoreConnector(),
verticalSpaceLarge,
_buildBodyContent(),
],
),
),
),
),
),
);
}
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: Colors.black87,
fontSize: 35));
});
}
return StoreConnector<AppState, KassaState>(
converter: (store) => store.state.kassaState!,
builder: (_, vm) {
return Text('${totalKassa(vm.kassaItems!)} тнг',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 35));
});
}
Expanded _buildBodyContent() {
return Expanded(
child: Column(
children: <Widget>[
TextField(
keyboardType: TextInputType.number,
controller: _iinController,
maxLength: 12,
decoration: InputDecoration(
labelText: 'ИИН Покупателя', hintText: "Введите ИИН покупателя"),
),
Container(
height: 150,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: BusyButton(
title: 'Оплатить картой',
onPressed: () {
pressPayment('card', null);
},
mainColor: primaryColor,
)),
horizontalSpaceSmall,
Expanded(
child: BusyButton(
title: 'Мобильный',
onPressed: () {
pressPayment('mobile', null);
},
mainColor: redColor,
)),
horizontalSpaceSmall,
Expanded(
child: BusyButton(
title: 'Наличными',
onPressed: () {
pressPayment('cash', null);
},
mainColor: greenColor,
)),
],
),
),
verticalSpaceLarge,
_nfsButtonRender(),
verticalSpaceSmall,
Expanded(
child: Container(),
),
Container(
child: BusyButton(
title: 'Отмена',
onPressed: () {
Navigator.pop(context);
},
mainColor: redColor,
)),
],
),
);
}
Widget _nfsButtonRender() {
if (!isBankApiAccess || widget.model.operationType != OperationTypePay) {
return Container();
}
return StoreConnector<AppState, AppState>(
converter: (store) => store.state,
builder: (_, _state) {
BankState state = _state.bankState!;
double _total;
if (widget.model.mode == SettingModeCalc) {
String value = totalCalc(_state.calcState!.calcItems!);
_total = double.parse(value);
} else {
String value = totalKassa(_state.kassaState!.kassaItems!);
_total = double.parse(value);
}
if (state.password == null || state.login == null ||
state.password!.length < 1 || state.login!.length < 1) {
return Container();
}
final bool isForteSessionActive = state.sessionType == 'Forte';
final String imageAsset = isForteSessionActive
? 'assets/images/fortepos.png'
: 'assets/images/halykpos.png';
final Color sessionColor = isForteSessionActive ? forteColor : halykColor;
final Future<AmanDao<CardData>> Function(double) paymentMethod =
isForteSessionActive ? paymentFortePos : paymentHalykPos;
return InkWell(
onTap: isBusy ?
() {} :
() async {
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 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
setState(() {
isBusy = true;
});
try {
await Redux.store!.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> data = await paymentMethod(_total);
if (data.success == true) {
pressPayment('card', data.data);
} else {
_dialogService.showDialog(description: data.msg ?? '');
}
} finally {
await Redux.store!.dispatch(changePinSkipFromSetting(false));
setState(() {
isBusy = false;
});
}
},
splashColor: halykColor.withOpacity(0.4),
borderRadius: BorderRadius.circular(10.0),
highlightColor: halykColor.withOpacity(0.1),
child: SizedBox(
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(80.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
image: AssetImage(imageAsset),
fit: BoxFit.fitWidth
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
),
);
}
);
}
pressPayment(String type, CardData? cardData) 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;
}
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,
contragent: _iinController.text
);
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.pop();
_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 if (!response.operation && response.body['message'] != null) {
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;
});
}
}
String totalKassa(List<ProductDao> kassaItems) {
num total = 0.0;
kassaItems.forEach((element) {
total += element.total == null ? 0.0 : element.total.toDouble();
});
return total.toString();
}
String 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.toString();
}
}
class PaymentModel {
String operationType;
String mode;
Voucher? voucher;
CardData? cardData;
PaymentModel(
{required this.mode, required this.operationType, this.voucher, this.cardData});
}