491 lines
14 KiB
Dart
491 lines
14 KiB
Dart
import 'package:checker/base/base_screen.dart';
|
|
import 'package:checker/db.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'dart:convert';
|
|
import 'dart:core';
|
|
import 'dart:async';
|
|
|
|
import 'package:checker/resources.dart';
|
|
import 'package:checker/strings.dart';
|
|
import 'package:checker/common.dart';
|
|
import 'package:checker/consts.dart';
|
|
import 'package:checker/network.dart';
|
|
import 'package:checker/base/base_state.dart';
|
|
import 'package:checker/screens/purchase_success.dart';
|
|
|
|
/// Экран проведения покупки.
|
|
class PurchaseScreen extends BaseScreen {
|
|
|
|
PurchaseScreen(helper, app, this.user, this.card) : super(helper, app);
|
|
|
|
final String user;
|
|
final String card;
|
|
|
|
@override
|
|
State createState() => new PurchaseScreenState<PurchaseScreen>(helper, app, user, card);
|
|
}
|
|
|
|
class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
|
|
/// Объект, помогающий вручную изменять введенный пользователем текст.
|
|
/// Используется для форматирования введенных пользователем данных
|
|
/// (удаляет запрещенные символы до их отображаения).
|
|
TextEditingController controller = new TextEditingController();
|
|
|
|
TextEditingController bonusController = new TextEditingController();
|
|
|
|
FocusNode _focusNodeSum = new FocusNode();
|
|
FocusNode _focusNodeBonus = new FocusNode();
|
|
|
|
bool isAutomaticallyImplyLeading() => false;
|
|
|
|
PurchaseScreenState(SqliteHelper helper, String app, String userString, String card) : super(helper, app) {
|
|
this.user = JSON.decode(userString);
|
|
this.card = card;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
loading = true;
|
|
requestAsyncData(user);
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext ctx) {
|
|
return getMainWidget();
|
|
}
|
|
|
|
bool purchaseInProgress = false;
|
|
Map user;
|
|
String card = '';
|
|
String loyalityType = '';
|
|
String loyalty = '';
|
|
String bonus = '';
|
|
List<Map> coupons = [];
|
|
|
|
@override
|
|
Widget getScreenContent() {
|
|
List<Widget> widgetList = [];
|
|
widgetList.add(getValueWithDescription(
|
|
StringsLocalization.buyer(),
|
|
user['first_name'] == null ? '' : user['first_name']
|
|
));
|
|
widgetList.add(getValueWithDescription(StringsLocalization.card(), card));
|
|
|
|
if (app != 'crypto') {
|
|
widgetList.add(getValueWithDescription(StringsLocalization.reward(), loyalty));
|
|
}
|
|
|
|
if (bonus.length > 0) {
|
|
if (app = 'crypto') {
|
|
widgetList.add(getValueWithDescription(StringsLocalization.joys(), bonus));
|
|
} else {
|
|
widgetList.add(getValueWithDescription(StringsLocalization.bonus(), bonus));
|
|
}
|
|
}
|
|
|
|
widgetList.add(getHintLabel());
|
|
widgetList.add(getInputField()); // Нельзя добавить еще одно поле таким же способом
|
|
|
|
if (app != 'autobonus') {
|
|
|
|
if (this.loyalityType == 'bonus') {
|
|
widgetList.add(getBonusInputField());
|
|
}
|
|
|
|
if (this.coupons.length > 0) {
|
|
widgetList.add(getItemTitle(StringsLocalization.selectCoupons()));
|
|
this.coupons.forEach((couponItem) {
|
|
widgetList.add(getItemToggleSwitch(
|
|
couponItem['offer_name'],
|
|
couponItem['coupon_condition'],
|
|
couponItem['isSet'],
|
|
(val) {
|
|
setState(() {
|
|
couponItem['isSet'] = val;
|
|
});
|
|
}
|
|
));
|
|
});
|
|
}
|
|
}
|
|
|
|
widgetList.add(wrapButton(getScreenMargins(36.0), getCompleteButton()));
|
|
|
|
widgetList.add(wrapButton(
|
|
getScreenMargins(24.0),
|
|
getScanButton(
|
|
context,
|
|
StringsLocalization.scan(),
|
|
Resources.getPrimaryColor(app)
|
|
)
|
|
));
|
|
|
|
return new Column(children: <Widget>[
|
|
new Expanded(
|
|
child: new ListView(children: widgetList))
|
|
]);
|
|
}
|
|
|
|
getBonusInputField() {
|
|
|
|
if (app = 'crypto') {
|
|
var bonusTextField = new EnsureVisibleWhenFocused(
|
|
focusNode: _focusNodeBonus,
|
|
child: new TextField(
|
|
focusNode: _focusNodeBonus,
|
|
keyboardType: TextInputType.number,
|
|
decoration: new InputDecoration.collapsed(
|
|
hintText: StringsLocalization.joysHint(),
|
|
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
|
|
),
|
|
controller: bonusController,
|
|
onSubmitted: (String text) {
|
|
setState(() {
|
|
bonusController.text = text;
|
|
});
|
|
},
|
|
textAlign: TextAlign.center,
|
|
));
|
|
} else {
|
|
var bonusTextField = new EnsureVisibleWhenFocused(
|
|
focusNode: _focusNodeBonus,
|
|
child: new TextField(
|
|
focusNode: _focusNodeBonus,
|
|
keyboardType: TextInputType.number,
|
|
decoration: new InputDecoration.collapsed(
|
|
hintText: StringsLocalization.bonusHint(),
|
|
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
|
|
),
|
|
controller: bonusController,
|
|
onSubmitted: (String text) {
|
|
setState(() {
|
|
bonusController.text = text;
|
|
});
|
|
},
|
|
textAlign: TextAlign.center,
|
|
));
|
|
}
|
|
var bonusTextField = new EnsureVisibleWhenFocused(
|
|
focusNode: _focusNodeBonus,
|
|
child: new TextField(
|
|
focusNode: _focusNodeBonus,
|
|
keyboardType: TextInputType.number,
|
|
decoration: new InputDecoration.collapsed(
|
|
hintText: StringsLocalization.bonusHint(),
|
|
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
|
|
),
|
|
controller: bonusController,
|
|
onSubmitted: (String text) {
|
|
setState(() {
|
|
bonusController.text = text;
|
|
});
|
|
},
|
|
textAlign: TextAlign.center,
|
|
));
|
|
|
|
return new Column(
|
|
children: <Widget>[
|
|
new Container(
|
|
margin: new EdgeInsets.only(
|
|
left: verticalMargin,
|
|
right: verticalMargin,
|
|
top: verticalMargin
|
|
),
|
|
padding: getInputFieldContainerPadding(),
|
|
decoration: getInputFieldContainerDecoration(),
|
|
child: bonusTextField
|
|
),
|
|
new Container(
|
|
margin: new EdgeInsets.only(
|
|
top: 5.0
|
|
),
|
|
child: new Text(
|
|
(app = 'crypto')?" ":StringsLocalization.bonusExplanation(),
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: new TextStyle(color: greyTextColor, fontSize: 11.0),
|
|
)
|
|
)
|
|
],
|
|
);
|
|
}
|
|
|
|
getScreenMargins(double top) {
|
|
double side = 42.0;
|
|
return new EdgeInsets.only(top: top, left: side, right: side);
|
|
}
|
|
|
|
getCompleteButton() {
|
|
return buildRaisedButton(
|
|
StringsLocalization.completePurchase(), () => onPurchaseClick());
|
|
}
|
|
|
|
Widget getScanButton(BuildContext context, String title, Color textColor) {
|
|
return new Container(
|
|
height: buttonHeight,
|
|
child: new FlatButton(
|
|
child: new Text(title, style: new TextStyle(color: textColor)),
|
|
onPressed: () => restartScanner()),
|
|
decoration: new BoxDecoration(
|
|
border: new Border.all(
|
|
color: Resources.getButtonColor(app), width: 1.0),
|
|
borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
|
|
}
|
|
|
|
@override
|
|
String getTitle() {
|
|
return StringsLocalization.carryingPurchase();
|
|
}
|
|
|
|
@override
|
|
getHintString() {
|
|
return StringsLocalization.sum();
|
|
}
|
|
|
|
@override
|
|
getTextWidget() {
|
|
// ?? TODO переделать, т.к. позволяет иметь только одно поле ввода на странице
|
|
return new EnsureVisibleWhenFocused(
|
|
focusNode: _focusNodeSum,
|
|
child: new TextField(
|
|
focusNode: _focusNodeSum,
|
|
keyboardType: TextInputType.number,
|
|
decoration: new InputDecoration.collapsed(
|
|
hintText: getHintString(),
|
|
hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
|
|
controller: controller,
|
|
onSubmitted: (String text) {
|
|
setState(() {
|
|
controller.text = _parseSum(text);
|
|
});
|
|
},
|
|
textAlign: TextAlign.center,
|
|
autofocus: true
|
|
));
|
|
}
|
|
|
|
requestAsyncData(Map user) async {
|
|
bool showBonus = await platform.invokeMethod('showBonus');
|
|
if (await platform.invokeMethod('isOnline')) {
|
|
var response, couponResponse;
|
|
print(user['coupons_url']);
|
|
try {
|
|
var token = await helper.getToken();
|
|
response = await getLoyaltyRequest(user['loyalty_url'], token);
|
|
couponResponse = await getCouponsRequest(
|
|
user['coupons_url'] + '?status=ACTIVE',
|
|
token
|
|
);
|
|
} catch(error) {
|
|
print(error.toString());
|
|
}
|
|
Map loyality = JSON.decode(response.body);
|
|
Map coupons = JSON.decode(couponResponse.body);
|
|
|
|
coupons['results'].forEach((couponItem) {
|
|
couponItem['isSet'] = false;
|
|
});
|
|
setState(() {
|
|
loading = false;
|
|
this.coupons = coupons['results'];
|
|
this.loyalityType = loyality['type'];
|
|
setBonuses(loyality, showBonus);
|
|
});
|
|
}
|
|
}
|
|
|
|
// TODO: Переделать, если потребуется
|
|
String _cleanupNumber(String text) {
|
|
String tmp = text
|
|
.replaceAll(' ', '')
|
|
.replaceAll('-', '')
|
|
.replaceAll(',', '.')
|
|
.replaceAll('..', '.');
|
|
|
|
while (tmp.indexOf('..') != -1) {
|
|
tmp = tmp.replaceAll('..', '.');
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
_parseSum(String input) {
|
|
num sumTotal = 0.0;
|
|
String text = _cleanupNumber(input);
|
|
|
|
try {
|
|
sumTotal = num.parse(text);
|
|
} catch (exception) {
|
|
print(exception);
|
|
try {
|
|
int idx = text.indexOf('.');
|
|
String integerPart = text.substring(0, idx);
|
|
String fractionalPart = text.substring(idx + 1, text.length);
|
|
if (fractionalPart.length > 2) {
|
|
fractionalPart = fractionalPart.substring(0, 2);
|
|
}
|
|
return '$integerPart.$fractionalPart';
|
|
} catch (exception) {
|
|
print(exception);
|
|
}
|
|
}
|
|
print(sumTotal.toStringAsFixed(2));
|
|
return sumTotal.toStringAsFixed(2);
|
|
}
|
|
|
|
onPurchaseClick() {
|
|
String val = _parseSum(controller.text);
|
|
helper.getCurrency().then((currency) {
|
|
print(currency.toString());
|
|
showDialog(
|
|
context: context,
|
|
child: new AlertDialog(
|
|
title: new Text(StringsLocalization.confirmation()),
|
|
content:
|
|
new Text(
|
|
StringsLocalization.confirmPurchase(val, currency)
|
|
),
|
|
actions: <Widget>[
|
|
new FlatButton(
|
|
child: new Text(StringsLocalization.no()),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
},
|
|
),
|
|
new FlatButton(
|
|
child: new Text(StringsLocalization.yes()),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
purchase(val);
|
|
},
|
|
)
|
|
]));
|
|
});
|
|
}
|
|
|
|
apiErrorAlert(String errorText) {
|
|
showDialog(
|
|
context: context,
|
|
child: new AlertDialog(
|
|
content: new Text(errorText),
|
|
actions: <Widget>[
|
|
new FlatButton(
|
|
child: new Text('Ok'),
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
},
|
|
)
|
|
]
|
|
)
|
|
);
|
|
}
|
|
|
|
purchase(String sumTotal) async {
|
|
setState(() {
|
|
loading = true;
|
|
});
|
|
if (await platform.invokeMethod('isOnline')) {
|
|
if (!purchaseInProgress) {
|
|
purchaseInProgress = true;
|
|
|
|
String token = await helper.getToken();
|
|
var result = await helper.getMerchantID();
|
|
var currency = await helper.getCurrency();
|
|
var couponIds = [];
|
|
|
|
this.coupons.forEach((item) {
|
|
if (item['isSet'] == true) couponIds.add(item['id']);
|
|
});
|
|
|
|
print(couponIds);
|
|
|
|
var body = {
|
|
'doc_id': result,
|
|
'curr_iso_code': currency.toString(),
|
|
'commit': 'true',
|
|
'sum_total': sumTotal,
|
|
};
|
|
|
|
if (bonusController.text.length > 0) {
|
|
body['bonus_payment'] = bonusController.text;
|
|
}
|
|
|
|
if (couponIds.length > 0) {
|
|
body['coupons'] = couponIds.join(",");
|
|
}
|
|
|
|
var purchaseResponse;
|
|
Map purchase;
|
|
|
|
try {
|
|
purchaseResponse = await getPurchaseRequest(user['purchases_url'], body, token);
|
|
purchase = JSON.decode(purchaseResponse.body);
|
|
} catch(error) {
|
|
purchaseInProgress = false;
|
|
print(error.toString());
|
|
}
|
|
|
|
if (purchase.containsKey('errors')) {
|
|
setState(() {
|
|
loading = false;
|
|
});
|
|
List<String> errors = purchase['errors'];
|
|
purchaseInProgress = false;
|
|
apiErrorAlert(errors[0]);
|
|
} else {
|
|
var couponsResponse;
|
|
|
|
try {
|
|
couponsResponse = await getCouponsRequest(purchase['coupons_url'], token);
|
|
print(couponsResponse.body);
|
|
} catch(error) {
|
|
purchaseInProgress = false;
|
|
print(error.toString());
|
|
}
|
|
|
|
Map coupons = JSON.decode(couponsResponse.body);
|
|
|
|
new Future.delayed(const Duration(milliseconds: 200), () {
|
|
print('show purchase success!');
|
|
var route = new MaterialPageRoute<String>(builder: (BuildContext context) => new PurchaseSuccessScreen(
|
|
sumTotal,
|
|
user['first_name'] == null ? '' : user['first_name'],
|
|
helper,
|
|
app,
|
|
purchase,
|
|
coupons['results']
|
|
), fullscreenDialog: true);
|
|
Navigator.of(context).push(route).then((token) {
|
|
Navigator.of(context).pop(token);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void setBonuses(Map bonuses, bool showBonus) {
|
|
print('kifio ' + this.loyalityType);
|
|
if (bonuses['type'] == 'amount') {
|
|
this.loyalty = '${user['discount']}%';
|
|
} else {
|
|
double loyaltyVal = (double.parse(bonuses['amount_to_bonus'][1]) /
|
|
bonuses['amount_to_bonus'][0]) * 100;
|
|
this.loyalty = '${loyaltyVal.toStringAsFixed(0)}%';
|
|
}
|
|
|
|
if (showBonus && (this.loyalityType == 'bonus')) {
|
|
this.bonus = '${user['bonus']}';
|
|
}
|
|
print('kifio ' + this.loyalty);
|
|
print('bonus ' + this.bonus);
|
|
}
|
|
|
|
restartScanner() {
|
|
helper.getToken().then((token) {
|
|
Navigator.of(context).pop(token);
|
|
});
|
|
}
|
|
}
|