Merge branch 'backend_nfc' into ns_bank_merge

# Conflicts:
#	lib/core/logger.dart
#	lib/core/models/check_data.dart
#	lib/core/router.dart
#	lib/core/services/DataService.dart
#	lib/main.dart
#	lib/redux/store.dart
#	lib/views/check/image_show_container.dart
#	lib/views/history/history_view.dart
#	lib/views/home/home_view_m.dart
#	lib/views/home/tabs/AdditionalTab.dart
#	lib/views/login/login_view.dart
#	lib/views/payment/payment_view.dart
#	lib/views/start_up/start_up_view.dart
#	pubspec.lock
#	pubspec.yaml
migrate_to_ns
error500 2022-01-25 17:04:36 +06:00
commit 0345a310e5
74 changed files with 4782 additions and 246 deletions

View File

@ -50,6 +50,7 @@ android {
targetSdkVersion 30 targetSdkVersion 30
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -62,16 +63,37 @@ android {
} }
} }
buildTypes { buildTypes {
// all {
// buildConfigField ("String[]", "SUPPORTED_DEVICES", collectSupportedDevicesToArray())
// }
debug { debug {
shrinkResources false shrinkResources false
minifyEnabled false minifyEnabled false
useProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
defaultConfig {
minSdkVersion 24
}
} }
release { release {
signingConfig signingConfigs.release
shrinkResources false shrinkResources false
minifyEnabled false minifyEnabled false
useProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
} }
} }
compileOptions {
//coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
} }
flutter { flutter {
@ -79,8 +101,28 @@ flutter {
} }
dependencies { dependencies {
//coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
implementation 'com.android.support:multidex:1.0.3'
//m4bank dependencies
} }
//def collectSupportedDevicesToArray() {
// return '{' + rootProject.ext."supportedDevices${getProject().name}".collect {
// "\"${it}\""
// }.join(",") + '}'
//}

26
android/app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,26 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\android_sdk\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
#Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
#M4Bank Wrapper
-keep class java9.util.stream.** { *; }

View File

@ -1,51 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="kz.com.aman.kassa"> xmlns:tools="http://schemas.android.com/tools"
<!-- io.flutter.app.FlutterApplication is an android.app.Application that package="kz.com.aman.kassa"> <!--
io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method. calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. --> FlutterApplication and put your custom class here.
-->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application <application
tools:replace="android:label"
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="Аман Касса"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="Аман Касса"
android:allowBackup="false"
android:roundIcon="@mipmap/ic_launcher_rounded" android:roundIcon="@mipmap/ic_launcher_rounded"
> >
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- <meta-data
<!--
<meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme"
/> --> />
<!-- <meta-data -->
<!--
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/splash" android:resource="@drawable/splash"
/> --> />
-->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!--
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
-->
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
</application> </application>
</manifest>
</manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,43 @@
package kz.com.aman.kassa.model;
import java.util.ArrayList;
import java.util.List;
public class AmanDao<E> {
private boolean success;
private String msg;
private E data;
private List<E> rows = new ArrayList<>();
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
public List<E> getRows() {
return rows;
}
public void setRows(List<E> rows) {
this.rows = rows;
}
}

View File

@ -0,0 +1,58 @@
package kz.com.aman.kassa.model;
public class CardData {
private Integer transactionNumber;
private String cardExpiryDate;
private String cardNumber;
private String transactionType;
private String cardPaymentSystemType;
private String authorizationCode;
public String getAuthorizationCode() {
return authorizationCode;
}
public void setAuthorizationCode(String authorizationCode) {
this.authorizationCode = authorizationCode;
}
public String getCardExpiryDate() {
return cardExpiryDate;
}
public void setCardExpiryDate(String cardExpiryDate) {
this.cardExpiryDate = cardExpiryDate;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getTransactionType() {
return transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public String getCardPaymentSystemType() {
return cardPaymentSystemType;
}
public void setCardPaymentSystemType(String cardPaymentSystemType) {
this.cardPaymentSystemType = cardPaymentSystemType;
}
public Integer getTransactionNumber() {
return transactionNumber;
}
public void setTransactionNumber(Integer transactionNumber) {
this.transactionNumber = transactionNumber;
}
}

View File

@ -0,0 +1,60 @@
package kz.com.aman.kassa.model;
import java.sql.Timestamp;
public class TransactionDao {
String cardType;
String cardExpireDate;
String cardNumber;
String transactionType;
Long amount;
String date;
public void setDate(String date) {
this.date = date;
}
public String getDate() {
return date;
}
public String getCardType() {
return cardType;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
public String getCardExpireDate() {
return cardExpireDate;
}
public void setCardExpireDate(String cardExpireDate) {
this.cardExpireDate = cardExpireDate;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getTransactionType() {
return transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
}

View File

@ -0,0 +1,307 @@
package kz.com.aman.kassa.plugins;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Build;
import com.google.gson.Gson;
import java.util.List;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import kz.com.aman.kassa.MainActivity;
import kz.com.aman.kassa.model.AmanDao;
enum OperationType {
PAYMENT, // payment
REFUND, // return
REVERSAL, // cancel
CLOSE_DAY, // closing of the trading day
OPERATIONS_LIST // get the list of operations
}
public class BankNfcPlugins implements MethodCallHandler {
private final Gson gson = new Gson();
//main activity
private MainActivity activity;
public MainActivity getActivity() {
return this.activity;
}
public BankNfcPlugins(MainActivity activity) {
this.activity = activity;
}
@Override
public void onMethodCall(MethodCall call, Result result) {
switch (call.method) {
case "init":
init(call, result);
break;
case "permissions":
permissions(result);
break;
case "connection":
connection(result);
break;
case "currency":
currency(result);
break;
case "auth":
authentication(call, result);
break;
case "pay":
pay(call, result);
break;
case "cancel":
cancel(call, result);
break;
case "shutdown":
shutdown(call, result);
break;
case "closeDay":
closeDay(call, result);
break;
case "transaction":
showTransaction(call, result);
break;
case "findTransaction":
findTransaction(call, result);
break;
case "refund":
refund(call, result);
break;
case "version":
result.success(String.valueOf(Build.VERSION.SDK_INT));
break;
case "get":
AmanDao<String> dao = new AmanDao<>();
dao.setSuccess(true);
dao.setMsg("Hello World");
result.success(gson.toJson(dao));
break;
case "error":
result.error("0-code","0-message", "0-details");
break;
default:
result.notImplemented();
}
}
private static int getVersion() {
String version = System.getProperty("java.version");
if(version.startsWith("1.")) {
version = version.substring(2, 3);
} else {
int dot = version.indexOf(".");
if(dot != -1) { version = version.substring(0, dot); }
} return Integer.parseInt(version);
}
private void permissions(Result result) {
// try {
// PermissionsManager.PermissionsCheckResultHandler permissionsCheckResultHandler =
// new PermissionsManager.PermissionsCheckResultHandler() {
// @Override
// public void onPermissionsGranted() {
// activity.runOnUiThread(() -> {
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(true);
// dao.setMsg("OK");
// result.success(gson.toJson(dao));
// }
// );
//
// }
//
// @Override
// public void onPermissionsDeclined() {
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(false);
// dao.setMsg("decline");
// result.success(gson.toJson(dao));
// }
// };
// permissionsManager = new PermissionsManagerImpl(this.activity);
// permissionsManager.checkPermissions(permissionsCheckResultHandler);
//
//
// } catch (Exception e) {
// result.error("1", e.getMessage(), e.getLocalizedMessage());
// }
}
private void init(MethodCall call, Result result) {
String serverUrl = call.argument("serverUrl");
String token = call.argument("token");
start(token);
AmanDao<String> dao = new AmanDao<>();
dao.setSuccess(true);
dao.setMsg("OK");
result.success(gson.toJson(dao));
}
//start after all permissions granted
private void start(String token) {
// clientInterface = M4BankMposClient.getInstance(
// new M4BankMposParameters(
// Format.JSON,
// "rus",
// null,
// this.activity,
// new SessionExpiringCallbackHandlerImpl(),
// "appName",
// ServerChoose.API_5_0,
// new ConfigurationSettings
// .Builder()
// .printerUsed(true)
// .umkaEnabled(true)
// .networkConfiguration(createNetworkConfiguration(serverUrl))
// .terminalConfiguration(createTerminalConfiguration())
// .build())
// );
}
private void connection(Result result) {
// clientInterface.getConfigurationManager()
// .checkConnection(
// new ConnectionCheckHandlerImpl(this.activity, result));
}
private void currency(Result result) {
// CurrencyDataHolder dataHolder = clientInterface.getConfigurationManager()
// .getCurrencyDataHolder();
// Currency currentCurrency = dataHolder.getCurrency();
// if(currentCurrency!=null){
// System.out.println(currentCurrency.getName());
// System.out.println(currentCurrency.getCurrency3DigitCode());
// } else {
// System.out.println("currentCurrency is null");
// }
// System.out.println("===========================");
// if(currentCurrency == null || !"398".equalsIgnoreCase(currentCurrency.getCurrency3DigitCode()) ){
// List<Currency> currencies = dataHolder.getCurrencyList();
// boolean changed = false;
// for(Currency currency : currencies ){
// System.out.println(currency.getName());
// System.out.println(currency.getLetterCode());
// System.out.println(currency.getCurrency3DigitCode());
// if("398".equalsIgnoreCase(currency.getCurrency3DigitCode())){
// dataHolder.setCurrency(currency);
// changed = true;
// break;
// }
// }
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(changed);
// dao.setMsg("current currency " + (currentCurrency!=null ? currentCurrency.getLetterCode() : "NULL"));
// result.success(gson.toJson(dao));
// } else {
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(true);
// dao.setMsg("exist");
// result.success(gson.toJson(dao));
// }
}
private void authentication(MethodCall call, Result result) {
// String login = call.argument("login");
// String password = call.argument("password");
// clientInterface.getAuthorizationManager().authorize(new AuthorizationHandlerImpl(this, result, login, password) );
}
private void pay(MethodCall call, Result result) {
// try {
// Integer value = call.argument("amount");
// long amount = value.longValue();
// clientInterface.cancel();
// clientInterface.getTransactionManager().makeCardPayment(new CardPaymentHandlerImpl(this, result, amount, TransactionTypeConv.PAYMENT));
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
private void findTransaction(MethodCall call, Result result) {
// try {
// Integer transactionNumber = call.argument("transactionNumber");
// String authorizationCode = call.argument("authorizationCode");
// clientInterface.getTransactionManager()
// .getTransactionsList(new CardRefundAmanHandlerImpl(this, result, transactionNumber, authorizationCode , transaction), 1000,
// 0, GetOperationType.SHOW, null);
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
private void refund(MethodCall call, Result result) {
// try {
// clientInterface.getTransactionManager()
// .makeCardRefund(new CardRefundAmanHandlerImpl(this, result, null, null, transaction));
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
private void closeDay(MethodCall call, Result result) {
// try {
// clientInterface.cancel();
// clientInterface.getTransactionManager().closeDay(new CloseDayHandlerImpl(this, result));
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
private void showTransaction(MethodCall call, Result result){
// clientInterface.getTransactionManager()
// .getTransactionsList(
// new TransactionDetailsHandlerImpl(this),
// 20, 0,
// GetOperationType.SHOW,
// null);
}
private void cancel(MethodCall call, Result result) {
// try {
// clientInterface.cancel();
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(true);
// dao.setMsg("OK");
// result.success(gson.toJson(dao));
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
private void shutdown(MethodCall call, Result result) {
// try {
// clientInterface.shutdown();
// AmanDao<String> dao = new AmanDao<>();
// dao.setSuccess(true);
// dao.setMsg("OK");
// result.success(gson.toJson(dao));
// } catch (Exception e) {
// System.out.println("=============>ERROR:"+e.getMessage());
// result.error("2", e.getMessage(), e.getLocalizedMessage());
// }
}
}

View File

@ -1,83 +1,149 @@
package kz.com.aman.kassa package kz.com.aman.kassa
import android.content.Context import android.app.Activity
import android.content.ContextWrapper import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.os.Build
import android.content.pm.PackageManager import android.widget.Toast
import android.net.Uri
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.annotation.NonNull import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant import io.flutter.plugins.GeneratedPluginRegistrant
import kz.com.aman.kassa.bank.JsonForExternalCall
import kz.com.aman.kassa.bank.OperationType
class MainActivity: FlutterActivity() { class MainActivity : FlutterActivity() {
private val CHANNEL = "samples.flutter.dev/battery" private val externalApplicationRequestCode = 207
private val externalOperationTypeKey = "ru.m4bank.ExternalApplication.OperationTypeKey"
private val externalInputDataKey = "ru.m4bank.ExternalApplication.InputDataKey"
private val externalResultDataKey = "ru.m4bank.ExternalApplication.ResultDataKey"
private val bankChannel = "channel:com.amanKassa/bank"
private lateinit var _result: MethodChannel.Result
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine); GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { //MethodChannel(flutterEngine.dartExecutor.binaryMessenger, BANK_CHANNEL).setMethodCallHandler(BankNfcPlugins(this))
// Note: this method is invoked on the main thread.
call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) { MethodChannel(flutterEngine.dartExecutor.binaryMessenger, bankChannel).setMethodCallHandler { call, result ->
result.success(batteryLevel) _result = result
} else { when (call.method) {
result.error("UNAVAILABLE", "Battery level not available.", null) "pay" -> {
operationPayment(call)
} }
} else if (call.method == "sendMessage") { "refund" -> {
val batteryLevel = sendMessage() operationRefund(call)
}
if (batteryLevel != -1) { "reversal" -> {
result.success(batteryLevel) operationReversal(call)
} else { }
result.error("UNAVAILABLE", "Battery level not available.", null) "closeDay" -> {
operationCloseDay(call)
}
"version" -> {
result.success(Build.VERSION.SDK_INT.toString())
}
else -> {
result.notImplemented()
} }
} else {
result.notImplemented()
} }
} }
} }
private fun getBatteryLevel(): Int { // private fun getOperationList(call: MethodCall) {
val batteryLevel: Int // val token: String = call.argument<String>("token").toString()
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { // val operationParameters = createOperationParameters(token)
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager // startOperation(OperationType.OPERATIONS_LIST,
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) // JsonForExternalCall.getOperationsListJson(operationParameters.authToken))
} else { //
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) // }
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
private fun operationPayment(call: MethodCall) {
val token = call.argument<String>("token").toString()
var amount: Long = 0
if (call.argument<Long>("amount") != null) {
amount = call.argument<Long>("amount")!!.toLong()
} }
println("batteryLevel"); val operationParameters = createOperationParameters(token)
println(batteryLevel); startOperation(OperationType.PAYMENT, JsonForExternalCall.getPaymentCardJson(operationParameters.authToken, amount.toString()))
return batteryLevel
} }
private fun sendMessage(): Int { private fun operationRefund(call: MethodCall) {
val packageManager: PackageManager = context.packageManager val token = call.argument<String>("token").toString()
val i = Intent(Intent.ACTION_VIEW) val terminalId = call.argument<String>("terminalId").toString()
try { val operDay = call.argument<String>("operDay").toString()
val mobileNo: String = "77774904900" //call.argument("mobileNo") val transNum = call.argument<String>("transNum").toString()
val message: String = "Hello world" //call.argument("message") val amount = call.argument<String>("amount").toString()
//https://wa.me/919167370647?text=Yes%20We'll%20do%20this%20in%20frag4%20inOCW val operationParameters = createOperationParameters(token)
println("mobileNo: $mobileNo message: $message") startOperation(OperationType.REFUND, JsonForExternalCall.getRefundCardJson(operationParameters.authToken, terminalId, operDay, transNum, amount))
val url = "https://wa.me/" + mobileNo.trim { it <= ' ' } + "?text=" + message.trim { it <= ' ' }
i.setPackage("com.whatsapp")
i.data = Uri.parse(url)
if (i.resolveActivity(packageManager) != null) {
context.startActivity(i)
}
println("finish method - 2")
} catch (e: Exception) {
e.printStackTrace()
}
return 25
} }
private fun operationReversal(call: MethodCall) {
val token = call.argument<String>("token").toString()
val terminalId = call.argument<String>("terminalId").toString()
val operDay = call.argument<String>("operDay").toString()
val transNum = call.argument<String>("transNum").toString()
val operationParameters = createOperationParameters(token)
val body = JsonForExternalCall.getReversalJson(operationParameters.authToken, terminalId, operDay, transNum);
println(body)
startOperation(OperationType.REVERSAL, body)
}
private fun operationCloseDay(call: MethodCall) {
val token = call.argument<String>("token").toString()
val operationParameters = createOperationParameters(token)
startOperation(OperationType.CLOSE_DAY, JsonForExternalCall.getCloseDayJson(operationParameters.authToken))
}
private fun createOperationParameters(token: String, operDay: String = "", terminalId: String = "", transNum: String = ""): OperationParameters {
return OperationParameters(authToken = token, operDay = operDay, terminalId = terminalId, transNum = transNum)
}
private fun startOperation(operationType: OperationType, inputJsonData: String?) {
val intent = Intent()
intent.component = ComponentName("ru.m4bank.softpos.halyk", "ru.m4bank.feature.externalapplication.ExternalApplicationActivity")
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
// intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra(externalOperationTypeKey, operationType.code)
intent.putExtra(externalInputDataKey, inputJsonData)
startActivityForResult(intent, externalApplicationRequestCode)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == externalApplicationRequestCode) {
println("---------------")
println(requestCode)
println(resultCode)
println(data)
if (data != null) {
println(data.getStringExtra(externalResultDataKey))
}
println("---------------")
if (requestCode == externalApplicationRequestCode && resultCode == Activity.RESULT_OK && data != null) {
println(data.getStringExtra(externalResultDataKey))
//Toast.makeText(this, data.getStringExtra(externalResultDataKey), Toast.LENGTH_LONG).show()
_result.success(data.getStringExtra(externalResultDataKey))
} else {
_result.error("008", "Error while apps connecting", "aaa")
//Toast.makeText(this, "Error while apps connecting", Toast.LENGTH_SHORT).show()
}
// if (resultCode == Activity.RESULT_OK) {
// _result.success(data?.getStringExtra("result"))
// } else if (resultCode == Activity.RESULT_CANCELED) {
// _result.error("008", "123","aaa")
// } else
// _result.success(null)
}
}
} }
data class OperationParameters(val authToken: String, val terminalId: String, val operDay: String, val transNum: String)

View File

@ -0,0 +1,3 @@
package kz.com.aman.kassa.bank;
data class ExternalPackage(val packageName: String, val activityName: String)

View File

@ -0,0 +1,142 @@
package kz.com.aman.kassa.bank;
object JsonForExternalCall {
fun getPaymentCardJson(authToken: String, amount: String): String {
return """{
"credentials" : {
"authorizationToken": "$authToken"
},
"operationData" : {
"instrument": "CARD",
"amountData" : {
"currencyCode": "398",
"amount": "$amount",
"amountExponent": "2"
},
"goods" : {
"product": [{
"name": "Товар",
"price": "$amount",
"quantity": "1",
"quantityExponent": "0",
"taxRate": "TAX_20",
"accountingSubject": "PRODUCT"
}]
}
}
}"""
}
fun getRefundCardJson(authToken: String, terminalId: String, operDay: String, transNum: String, amount: String): String {
return """{
"credentials" :{
"authorizationToken": "$authToken"
},
"operationData" :{
"instrument": "CARD",
"amountData" : {
"currencyCode": "348",
"amount": "6000",
"amountExponent": "2"
},
"parentTransaction" : {
"terminalId": "$terminalId",
"operationDay": "$operDay",
"transactionNumber": "$transNum"
}
}
}"""
}
fun getCloseDayJson(authToken: String): String {
return """{
"credentials" : {
"authorizationToken": "$authToken"
}
}"""
}
fun getOperationsListJson(authToken: String): String {
return """{
"credentials" : {
"authorizationToken": "$authToken"
},
"operationData": {
"params": {
"offset": "0",
"limit": "20"
},
"filter": {
"transactionTypes": [PAYMENT, REFUND]
}
}
}"""
}
fun getReversalJson(authToken: String, terminalId: String, operDay: String, transNum: String): String {
return """{
"credentials" : {
"authorizationToken": "$authToken"
},
"operationData" : {
"parentTransaction" : {
"terminalId": "$terminalId",
"operationDay": "$operDay",
"transactionNumber": "$transNum"
}
}
}"""
}
// fun getPaymentCashJson(authToken: String): String {
// return """{
// "credentials" : {
// "authorizationToken": "$authToken"
// },
// "operationData" : {
// "instrument": "CASH",
// "amountData" : {
// "currencyCode": "643",
// "amount": "6000",
// "amountExponent": "2"
// },
// "goods" : {
// "product": [{
// "name": "Печеньки",
// "price": "3000",
// "quantity": "2",
// "quantityExponent": "0",
// "taxRate": "TAX_20",
// "accountingSubject": "PRODUCT"
// }]
// }
// }
// }"""
// }
//
// fun getRefundCashJson(authToken: String, terminalId: String, operDay: String, transNum: String): String {
// return """{
// "credentials" :{
// "authorizationToken": "$authToken"
// },
// "operationData" :{
// "instrument": "CASH",
// "amountData" : {
// "currencyCode": "643",
// "amount": "6000",
// "amountExponent": "2"
// },
// "parentTransaction" : {
// "terminalId": "$terminalId",
// "operationDay": "$operDay",
// "transactionNumber": "$transNum"
// }
// }
// }"""
// }
}

View File

@ -0,0 +1,9 @@
package kz.com.aman.kassa.bank;
enum class OperationType(val code: String) {
PAYMENT("PAYMENT"),
REFUND("REFUND"),
REVERSAL("REVERSAL"),
CLOSE_DAY("CLOSE_DAY"),
OPERATIONS_LIST("OPERATIONS_LIST")
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/design_default_color_background"
tools:context=".activities.BankActivity"
>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="32dp"
android:layout_marginRight="20dp">
<Button
android:id="@+id/buttonClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="myClickHandler"
tools:text="@android:string/cancel" />
<ImageView
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_alignParentRight="true"
android:src="@mipmap/ic_launcher_foreground" />
</RelativeLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>

View File

@ -0,0 +1,494 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".bank.M4BankActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/authorize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/authorize_button" />
<EditText
android:id="@+id/amountField"
android:layout_weight="1"
android:inputType="numberDecimal"
android:hint="@string/amount_hint"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/login_hint"
android:inputType="text" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/password_hint"
android:inputType="textPassword" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/logout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/logout_button" />
<!--<Button-->
<!--android:id="@+id/changePassword"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_gravity="center_horizontal"-->
<!--android:text="@string/change_password_button" />-->
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--<EditText-->
<!--android:id="@+id/oldPassword"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_weight="1"-->
<!--android:hint="@string/old_password_hint"-->
<!--android:inputType="textPassword" />-->
<!--<EditText-->
<!--android:id="@+id/newPassword"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_weight="1"-->
<!--android:hint="@string/new_password_hint"-->
<!--android:inputType="textPassword" />-->
</LinearLayout>
<!--<Button-->
<!--android:id="@+id/register"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="@string/register_button" />-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--<EditText-->
<!--android:id="@+id/code"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_weight="1"-->
<!--android:hint="@string/code_hint"-->
<!--android:inputType="number" />-->
<!--<EditText-->
<!--android:id="@+id/pin"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_weight="1"-->
<!--android:hint="@string/pin_hint"-->
<!--android:inputType="number" />-->
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp">
<Button
android:id="@+id/checkAccess"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/check_access" />
<Spinner
android:id="@+id/checkAccessSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/accessTypes" />
</LinearLayout>
<Button
android:id="@+id/getAccesses"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/get_available_operations" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<!--<Button-->
<!--android:id="@+id/setLanguage"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/set_language" />-->
<!--<Spinner-->
<!--android:id="@+id/setLanguageSpinner"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:entries="@array/languages" />-->
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/checkConnection"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/check_connection" />
<Button
android:id="@+id/getLicense"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/get_license" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/makeCardPayment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/make_card_payment" />
<Button
android:id="@+id/getCommonCardData"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/get_common_card_data" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/makeReversalLast"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/make_reversal_last" />
<Button
android:id="@+id/getCurrentTransactionDetails"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/get_current_transaction_details" />
<Button
android:id="@+id/completePayment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/complete_payment" />
</LinearLayout>
<Button
android:id="@+id/readerInformation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/reader_information" />
<Button
android:id="@+id/versionStore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/version_store" />
<Button
android:id="@+id/versionTracker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/version_tracker" />
<Button
android:id="@+id/makeReversalLastWithCallback"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_reversal_last_saved_operation" />
<Button
android:id="@+id/makeCashPayment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_cash_payment" />
<Button
android:id="@+id/makeAlipayPayment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_alipay_payment" />
<Button
android:id="@+id/makeCardRefund"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_card_refund" />
<!--<Button-->
<!--android:id="@+id/makeCardRefundWithD200"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/make_card_refund_with_d200" />-->
<Button
android:id="@+id/makeCashRefund"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_cash_refund" />
<!--<Button-->
<!--android:id="@+id/makeCashRefundWithD200"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/make_cash_refund_with_d200" />-->
<Button
android:id="@+id/makeAlipayRefund"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_alipay_refund" />
<!--<Button-->
<!--android:id="@+id/makeReversal"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/make_reversal" />-->
<Button
android:id="@+id/makeEasyReversal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_easy_reversal" />
<Button
android:id="@+id/makeEasyCardReversal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_easy_card_reversal" />
<Button
android:id="@+id/makeReversalSavedUnsuccessfulOperation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/makeReversalSavedUnsuccessfulOperation" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--<Button-->
<!--android:id="@+id/makeReconciliation"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/make_reconciliation" />-->
<!--<Button-->
<!--android:id="@+id/enterServiceMenu"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/enter_service_menu" />-->
</LinearLayout>
<!--<Button-->
<!--android:id="@+id/addAdditionalCardReader"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/add_additional_card_reader" />-->
<!--<Button-->
<!--android:id="@+id/getReadersInfo"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/get_readers_info" />-->
<Button
android:id="@+id/getMerchantUsers"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/get_merchant_users" />
<Button
android:id="@+id/resendReceipt"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/resend_receipt" />
<Button
android:id="@+id/getTransactionDetails"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/get_transaction_details" />
<Button
android:id="@+id/getTransactionListFilter"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/get_filter_list" />
<Button
android:id="@+id/activate"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/activate" />
<Button
android:id="@+id/addPrinter"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/add_new_printer" />
<Button
android:id="@+id/deletePrinter"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/delete_printer" />
<Button
android:id="@+id/printFiscal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_fiscal_check" />
<Button
android:id="@+id/printSlipCheck"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_slip_check" />
<Button
android:id="@+id/printTemplate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/print_template" />
<Button
android:id="@+id/printReportX"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_x_report" />
<Button
android:id="@+id/printReportZ"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_z_report" />
<Button
android:id="@+id/printFullReport"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_full_report" />
<Button
android:id="@+id/printShortReport"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/printing_short_report" />
<!--<Button-->
<!--android:id="@+id/executeExternalApplication"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="match_parent"-->
<!--android:text="@string/call_external_application" />-->
<Button
android:id="@+id/sendRegisterRequest"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/send_register_request" />
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/cancel_interface" />
<Button
android:id="@+id/ecomPayment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/make_ecom_payment" />
<Button
android:id="@+id/getAccessPaymentInstruments"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/get_access_payment_instruments" />
<Button
android:id="@+id/closeDay"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/close_day" />
<Button
android:id="@+id/writeTerminalKeys"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/write_terminal_keys" />
<Button
android:id="@+id/readBarCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/read_barcode" />
<Button
android:id="@+id/updateDictionary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/update_dictionary" />
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<TextView
android:id="@+id/labelMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:text="Choose element" />
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/labelMessage"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:cacheColorHint="#00000000"
android:divider="@android:color/transparent"
android:dividerHeight="1dp"
android:listSelector="@android:color/transparent" />
</RelativeLayout>

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="New Text"
android:textSize="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_3" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_4" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_5" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_6" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_7" />
<Button
android:id="@+id/button8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_8" />
<Button
android:id="@+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_9" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.36"
android:orientation="horizontal">
<Button
android:id="@+id/button0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_0" />
<Button
android:id="@+id/buttoncan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel" />
<Button
android:id="@+id/buttonconfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/confirm" />
<Button
android:id="@+id/buttonclean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clear" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/buttonstart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_start" />
<Button
android:id="@+id/buttonexit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pin_text_btn_exit" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/itemView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="20dp"
android:textColor="@android:color/black" />
</RelativeLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,107 @@
<resources>
<string name="app_name">TestAppM4bank</string>
<string name="authorize_button">Authorize</string>
<string name="logout_button">Log Out</string>
<string name="change_password_button">Change Password</string>
<string name="login_hint">Enter Your Login</string>
<string name="password_hint">Enter Your Password</string>
<string name="old_password_hint">Enter Old Password</string>
<string name="new_password_hint">Enter New Password</string>
<string name="register_button">Register</string>
<string name="code_hint">Enter Reader Code</string>
<string name="pin_hint">Enter Reader Pin</string>
<string name="serial_hint">Enter Reader Serial Number</string>
<string name="default_server_address1">http://10.10.0.245:29978</string>
<string name="default_server_address2">http://10.45.49.31:29978</string>
<string name="default_server_address_sber_test">http://sbertest.m4bank.ru:21017</string>
<!--<string name="default_server_address_mpos_5_0_test">http://217.174.185.218:35997</string>-->
<string name="default_server_address_mpos_5_0_test">http://185.98.84.231:2000</string>
<string name="check_access">Check access</string>
<string name="get_available_operations">Get available operations</string>
<string name="set_language">Set language</string>
<string name="check_connection">Check connection</string>
<string name="make_card_payment">Make card payment</string>
<string name="get_common_card_data">Get common card data</string>
<string name="add_additional_card_reader">Add additional card reader</string>
<string name="get_readers_info">Get readers info</string>
<string name="make_cash_payment">Make cash payment</string>
<string name="make_alipay_payment">Make alipay payment</string>
<string name="make_card_refund">Make card refund</string>
<string name="make_card_refund_with_d200">Make card refund with D200</string>
<string name="make_cash_refund_with_d200">Make easy cash refund</string>
<string name="make_alipay_refund">Make alipay refund</string>
<string name="make_cash_refund">Make cash refund</string>
<string name="make_reversal">Make reversal</string>
<string name="make_easy_reversal">Make easy reversal</string>
<string name="make_easy_card_reversal">Make easy card reversal</string>
<string name="makeReversalSavedUnsuccessfulOperation">make Reversal Saved Unsuccessful Operation</string>
<string name="make_reconciliation">Make reconciliation</string>
<string name="get_merchant_users">Get merchant users</string>
<string name="get_access_payment_instruments">Get access PI</string>
<string name="close_day">Close day</string>
<string name="write_terminal_keys">Write terminal keys</string>
<string name="read_barcode">Read BarCode</string>
<string name="update_dictionary">Update Dictionary</string>
<string-array name="accessTypes">
<item>Payment</item>
<item>Reversal</item>
<item>Refund</item>
<item>Cash</item>
<item>PartRefund</item>
<item>AddReader</item>
<item>CloseDay</item>
<item>AddPrinter</item>
<item>FuncPrinter</item>
</string-array>
<string-array name="languages">
<item>rus</item>
<item>eng</item>
</string-array>
<string name="confirm">confirm</string>
<string name="clear">clear</string>
<string name="cancel">cancel</string>
<string name="resend_receipt">Resend receipt</string>
<string name="get_transaction_details">Get transaction details</string>
<string name="get_filter_list">Get filter list</string>
<string name="activate">Activate</string>
<string name="add_new_printer">Add new printer</string>
<string name="delete_printer">Delete printer</string>
<string name="printing_fiscal_check">Printing fiscal check</string>
<string name="printing_slip_check">Printing slip check</string>
<string name="print_template">print template</string>
<string name="printing_x_report">Printing X report</string>
<string name="printing_z_report">Printing Z report</string>
<string name="printing_full_report">Printing full report</string>
<string name="printing_short_report">Printing short report</string>
<string name="call_external_application">Call external application</string>
<string name="send_register_request">Send register request</string>
<string name="cancel_interface">Cancel interface</string>
<string name="make_ecom_payment">Make ecom payment</string>
<string name="enter_service_menu">Enter service menu</string>
<string name="make_reversal_last_saved_operation">Make reversal last saved operation</string>
<string name="reader_information">Get reader information</string>
<string name="version_store">Store version</string>
<string name="version_tracker">Tracker version</string>
<string name="pin_text_btn_1">1</string>
<string name="pin_text_btn_2">2</string>
<string name="pin_text_btn_3">3</string>
<string name="pin_text_btn_4">4</string>
<string name="pin_text_btn_5">5</string>
<string name="pin_text_btn_6">6</string>
<string name="pin_text_btn_7">7</string>
<string name="pin_text_btn_8">8</string>
<string name="pin_text_btn_9">9</string>
<string name="pin_text_btn_0">0</string>
<string name="pin_text_btn_start">start</string>
<string name="pin_text_btn_exit">exit</string>
<string name="get_license">Get license</string>
<string name="make_reversal_last">Make reversal last</string>
<string name="get_current_transaction_details">Get current transaction details</string>
<string name="complete_payment">Complete payment</string>
<string name="amount_hint">Amount</string>
</resources>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--Set application-wide security config using base-config tag.-->
<base-config cleartextTrafficPermitted="false" />
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">kassa.aman.com.kz</domain>
<domain includeSubdomains="true">kassa.aman.systems</domain>
<domain includeSubdomains="true">partner.aman.com.kz</domain>
<domain includeSubdomains="true">partner.aman.systems</domain>
</domain-config>
</network-security-config>

View File

@ -7,8 +7,11 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.0' classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
allprojects { allprojects {
@ -16,6 +19,12 @@ allprojects {
google() google()
jcenter() jcenter()
} }
configurations.all {
resolutionStrategy {
cacheDynamicVersionsFor 2, 'minutes'
}
}
} }
rootProject.buildDir = '../build' rootProject.buildDir = '../build'
@ -29,3 +38,10 @@ subprojects {
task clean(type: Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = "1.8"
}
}

BIN
assets/images/NBK_Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
assets/images/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/images/halykpos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
assets/images/phone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
assets/images/phone_fit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -14,6 +14,7 @@ const String Voucher_columnUrl = 'url';
const String VoucherTypePayment = 'payment'; const String VoucherTypePayment = 'payment';
const String VoucherTypeReturnPay = 'returnPay'; const String VoucherTypeReturnPay = 'returnPay';
const String VoucherTypeReport = 'report'; const String VoucherTypeReport = 'report';
const String VoucherTypeCloseDayPosReport = 'closeDayPosReport';
class Voucher { class Voucher {
int? id; int? id;

22
lib/core/foo_test.dart Normal file
View File

@ -0,0 +1,22 @@
import 'dart:convert';
import 'package:aman_kassa_flutter/core/models/transaction_item.dart';
void main() {
var date = "2021-01-14T12:15:34.511Z";
String text = '{'+
'"amount": 5500,'+
'"cardExpireDate": "09/22",'+
'"cardNumber": "400303******6254",'+
'"cardType": "VISA",'+
'"date": "2021-01-14 12:22:09",'+
'"transactionType": "PAYMENT"'+
'}';
print(text);
dynamic data = json.decode(text);
TransactionItem item = TransactionItem.fromJson(data);
print(item.date);
}

View File

@ -1,5 +1,6 @@
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/DataService.dart';
import '../core/services/DbService.dart'; import '../core/services/DbService.dart';
@ -32,5 +33,7 @@ class LocatorInjector {
_log.d('Initializing DataService Service'); _log.d('Initializing DataService Service');
locator.registerLazySingleton<DataService>(() => DataService()); locator.registerLazySingleton<DataService>(() => DataService());
_log.d('Initializing BankService Service');
locator.registerLazySingleton<BankService>(() => BankService());
} }
} }

View File

@ -0,0 +1,17 @@
class AmanDao<T> {
final T? data;
final dynamic? rows;
final String? msg;
final bool? success;
AmanDao({this.data, this.success, this.msg, this.rows});
factory AmanDao.fromJson(Map<String, dynamic> data) {
return AmanDao(
data: data['data'],
msg: data['msg'],
success: data['success'],
rows: data['rows']);
}
}

View File

@ -0,0 +1,35 @@
class CardData {
final int? transactionNumber;
final int? operationDay;
final int? terminalId;
final String? cardNumber;
final String? cardholderName;
final String? authorizationCode;
final String? transactionType;
CardData({this.transactionNumber, this.operationDay, this.cardNumber, this.cardholderName, this.authorizationCode, this.terminalId, this.transactionType });
static CardData? fromJson(Map<String, dynamic>? json) {
return json != null ?
CardData(
transactionNumber: json['transactionNumber'],
operationDay: json['operationDay'],
terminalId: json['terminalId'],
cardNumber: json['cardNumber'],
cardholderName: json['cardholderName'],
authorizationCode: json['authorizationCode'],
transactionType: json['transactionType'],
)
: null;
}
Map<String, dynamic> toJson() =>
{
'transactionNumber': transactionNumber,
'operationDay': operationDay,
'cardNumber': cardNumber,
'cardholderName': cardholderName,
'authorizationCode': authorizationCode,
'terminalId' : terminalId,
'transactionType' : transactionType,
};
}

View File

@ -1,22 +1,26 @@
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/check_item.dart'; import 'package:aman_kassa_flutter/core/models/check_item.dart';
class CheckData { class CheckData {
final String ?type; final String ?type;
num? card; num? card;
final List<CheckItem>? items; final List<CheckItem>? items;
CheckData({this.type, this.card, this.items}); CardData? cardData;
CheckData({this.type, this.card, this.items, this.cardData});
static CheckData fromJson(Map<String, dynamic> json) { static CheckData fromJson(Map<String, dynamic> json) {
return CheckData( return CheckData(
type: json['type'], type: json['type'],
card: json['card'], card: json['card'],
items: json['items'], items: (json['items'] as List).map((e) => CheckItem.fromJson(e)).toList(),
cardData: CardData.fromJson(json['cardData'])
); );
} }
Map<String, dynamic> toJson() => Map<String, dynamic> toJson() =>
{ {
'type': type, 'type': type,
'card': card, 'card': card,
'items': items?.map((e) => e.toJson()).toList() 'items': items?.map((e) => e.toJson()).toList(),
'cardData': cardData?.toJson()
}; };
} }

View File

@ -0,0 +1,54 @@
import 'package:aman_kassa_flutter/core/models/transaction_item.dart';
import 'halyk/halyk_close_day_dao.dart';
class CloseDayData {
final String? title;
final num? totalAmount;
final int? totalCount;
final num? paymentAmount;
final int? paymentCount;
final num? refundAmount;
final int? refundCount;
final num? cancelAmount;
final int? cancelCount;
final List<TransactionBean>? items;
CloseDayData({
this.title,
this.items,
this.totalAmount, this.totalCount,
this.paymentAmount, this.paymentCount,
this.refundAmount, this.refundCount,
this.cancelAmount, this.cancelCount
});
static CloseDayData fromJson(Map<String, dynamic> json) {
return CloseDayData(
title: json['title'],
totalAmount: json['totalAmount'],
totalCount: json['totalCount'],
paymentAmount: json['paymentAmount'],
paymentCount: json['paymentCount'],
refundAmount: json['refundAmount'],
refundCount: json['refundCount'],
cancelAmount: json['cancelAmount'],
cancelCount: json['cancelCount'],
items: (json['items'] as List).map((e) => TransactionBean.fromMap(e)).toList(),
);
}
Map<String, dynamic> toJson() =>
{
'title': title,
'totalAmount': totalAmount,
'totalCount': totalCount,
'paymentAmount': paymentAmount,
'paymentCount': paymentCount,
'refundAmount': refundAmount,
'refundCount': refundCount,
'cancelAmount': cancelAmount,
'cancelCount': cancelCount,
'items': items?.map((e) => e.toJson()).toList(),
};
}

View File

@ -0,0 +1,180 @@
/// result : {"code":"0","description":"Successfully completed"}
/// transactions : {"transaction":[{"type":"PAYMENT","instrument":"CARD","amount":"6000","terminalId":"123321","operationDay":"4","transactionNumber":"69","instrumentSpecificData":{"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"}},{"type":"REFUND","instrument":"CARD","amount":"4500","terminalId":"123321","operationDay":"4","transactionNumber":"70","instrumentSpecificData":{"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"},"parentTransaction":{"terminalId":"123321","operationDay":"4","transactionNumber":"69"}}]}
/// closeDayResults : {"reconciliationResult":[{"hostResultCode":"000","hostResultDescription":"Success","terminalExternalId":"example_terminal_id"}]}
class HalykCloseDayDao {
ResultBean? result;
TransactionsBean? transactions;
CloseDayResultsBean? closeDayResults;
HalykCloseDayDao({ this.result, this.closeDayResults, this.transactions});
static HalykCloseDayDao? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
HalykCloseDayDao halykCloseDayDaoBean = HalykCloseDayDao();
halykCloseDayDaoBean.result = ResultBean.fromMap(map['result']);
halykCloseDayDaoBean.transactions = TransactionsBean.fromMap(map['transactions']);
halykCloseDayDaoBean.closeDayResults = CloseDayResultsBean.fromMap(map['closeDayResults']);
return halykCloseDayDaoBean;
}
Map toJson() => {
"result": result,
"transactions": transactions,
"closeDayResults": closeDayResults,
};
}
/// reconciliationResult : [{"hostResultCode":"000","hostResultDescription":"Success","terminalExternalId":"example_terminal_id"}]
class CloseDayResultsBean {
List<ReconciliationResultBean>? reconciliationResult;
static CloseDayResultsBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
CloseDayResultsBean closeDayResultsBean = CloseDayResultsBean();
closeDayResultsBean.reconciliationResult = List.empty()..addAll(
(map['reconciliationResult'] as List).map((o) => ReconciliationResultBean.fromMap(o))
);
return closeDayResultsBean;
}
Map toJson() => {
"reconciliationResult": reconciliationResult,
};
}
/// hostResultCode : "000"
/// hostResultDescription : "Success"
/// terminalExternalId : "example_terminal_id"
class ReconciliationResultBean {
String? hostResultCode;
String? hostResultDescription;
String? terminalExternalId;
static ReconciliationResultBean fromMap(Map<String, dynamic> map) {
ReconciliationResultBean reconciliationResultBean = ReconciliationResultBean();
reconciliationResultBean.hostResultCode = map['hostResultCode'];
reconciliationResultBean.hostResultDescription = map['hostResultDescription'];
reconciliationResultBean.terminalExternalId = map['terminalExternalId'];
return reconciliationResultBean;
}
Map toJson() => {
"hostResultCode": hostResultCode,
"hostResultDescription": hostResultDescription,
"terminalExternalId": terminalExternalId,
};
}
/// transaction : [{"type":"PAYMENT","instrument":"CARD","amount":"6000","terminalId":"123321","operationDay":"4","transactionNumber":"69","instrumentSpecificData":{"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"}},{"type":"REFUND","instrument":"CARD","amount":"4500","terminalId":"123321","operationDay":"4","transactionNumber":"70","instrumentSpecificData":{"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"},"parentTransaction":{"terminalId":"123321","operationDay":"4","transactionNumber":"69"}}]
class TransactionsBean {
List<TransactionBean>? transaction;
static TransactionsBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
TransactionsBean transactionsBean = TransactionsBean();
transactionsBean.transaction = List.empty()..addAll(
(map['transaction'] as List).map((o) => TransactionBean.fromMap(o))
);
return transactionsBean;
}
Map toJson() => {
"transaction": transaction,
};
}
/// type : "PAYMENT"
/// instrument : "CARD"
/// amount : "6000"
/// terminalId : "123321"
/// operationDay : "4"
/// transactionNumber : "69"
/// instrumentSpecificData : {"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"}
class TransactionBean {
String? type;
String? instrument;
num amount = 0;
int? terminalId;
int? operationDay;
int? transactionNumber;
InstrumentSpecificDataBean? instrumentSpecificData;
static TransactionBean fromMap(Map<String, dynamic> map) {
TransactionBean transactionBean = TransactionBean();
transactionBean.type = map['type'];
transactionBean.instrument = map['instrument'];
transactionBean.amount = map['amount'] ?? 0;
transactionBean.terminalId = map['terminalId'];
transactionBean.operationDay = map['operationDay'];
transactionBean.transactionNumber = map['transactionNumber'];
transactionBean.instrumentSpecificData = InstrumentSpecificDataBean.fromMap(map['instrumentSpecificData']);
return transactionBean;
}
Map toJson() => {
"type": type,
"instrument": instrument,
"amount": amount,
"terminalId": terminalId,
"operationDay": operationDay,
"transactionNumber": transactionNumber,
"instrumentSpecificData": instrumentSpecificData,
};
}
/// authorizationCode : "000000"
/// rrn : "1234567890"
/// cardholderName : "IVAN IVANOV"
/// maskedPan : "123456******7890"
class InstrumentSpecificDataBean {
String? authorizationCode;
String? rrn;
String? cardholderName;
String? maskedPan;
static InstrumentSpecificDataBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
InstrumentSpecificDataBean instrumentSpecificDataBean = InstrumentSpecificDataBean();
instrumentSpecificDataBean.authorizationCode = map['authorizationCode'];
instrumentSpecificDataBean.rrn = map['rrn'];
instrumentSpecificDataBean.cardholderName = map['cardholderName'];
instrumentSpecificDataBean.maskedPan = map['maskedPan'];
return instrumentSpecificDataBean;
}
Map toJson() => {
"authorizationCode": authorizationCode,
"rrn": rrn,
"cardholderName": cardholderName,
"maskedPan": maskedPan,
};
}
/// code : "0"
/// description : "Successfully completed"
class ResultBean {
int? code;
String? description;
ResultBean({this.code, this.description});
static ResultBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
ResultBean resultBean = ResultBean();
resultBean.code = map['code'];
resultBean.description = map['description'];
return resultBean;
}
Map toJson() => {
"code": code,
"description": description,
};
}

View File

@ -0,0 +1,75 @@
import 'package:intl/intl.dart';
class HalykPosSession {
const HalykPosSession(
{this.login,
this.token,
this.serverTime,
this.tokenTimeout,
this.result});
final String? login;
final String? token;
final DateTime? serverTime;
final int? tokenTimeout;
final ResultBean? result;
static HalykPosSession fromJson(Map<String, dynamic> data) => HalykPosSession(
login: data['login'],
token: data['token'],
result: ResultBean.fromMap(data['result']),
serverTime: data['ServerTime'] != null
? new DateFormat("dd.MM.yyyy HH:mm:ss ZZZ").parse(data['ServerTime'])
: null,
tokenTimeout: data['TokenTimeout']);
}
/// ServerTime : "25.06.2021 13:18:00 GMT+06:00"
/// ResultCode : "040"
/// ResultStr : "Unknown operator login. Check the correctness of the data or contact support."
/// Response : {"Code":"040","Description":"Unknown operator login. Check the correctness of the data or contact support."}
class ResultBean {
String? ServerTime;
String? ResultCode;
String? ResultStr;
ResponseBean? Response;
static ResultBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
ResultBean resultBean = ResultBean();
resultBean.ServerTime = map['ServerTime'];
resultBean.ResultCode = map['ResultCode'];
resultBean.ResultStr = map['ResultStr'];
resultBean.Response = ResponseBean.fromMap(map['Response']);
return resultBean;
}
Map toJson() => {
"ServerTime": ServerTime,
"ResultCode": ResultCode,
"ResultStr": ResultStr,
"Response": Response,
};
}
/// Code : "040"
/// Description : "Unknown operator login. Check the correctness of the data or contact support."
class ResponseBean {
String? Code;
String? Description;
static ResponseBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
ResponseBean responseBean = ResponseBean();
responseBean.Code = map['Code'];
responseBean.Description = map['Description'];
return responseBean;
}
Map toJson() => {
"Code": Code,
"Description": Description,
};
}

View File

@ -0,0 +1,155 @@
/// result : {"code":"0","description":"Successfully completed","hostResponse":{"code":"0","description":"Successfully completed"}}
/// transaction : {"terminalId":"123321","operationDay":"4","transactionNumber":"69","instrumentSpecificData":{"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"}}
class HalykResponse {
ResultBean? result;
TransactionBean? transaction;
HalykResponse({this.result, this.transaction});
static HalykResponse? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
HalykResponse halykResponseBean = HalykResponse();
halykResponseBean.result = ResultBean.fromMap(map['result']);
halykResponseBean.transaction = TransactionBean.fromMap(map['transaction']);
return halykResponseBean;
}
Map toJson() =>
{
"result": result,
"transaction": transaction,
};
}
/// terminalId : "123321"
/// operationDay : "4"
/// transactionNumber : "69"
/// instrumentSpecificData : {"authorizationCode":"000000","rrn":"1234567890","cardholderName":"IVAN IVANOV","maskedPan":"123456******7890"}
class TransactionBean {
int? terminalId;
int? operationDay;
int? transactionNumber;
InstrumentSpecificDataBean? instrumentSpecificData;
static TransactionBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
TransactionBean transactionBean = TransactionBean();
transactionBean.terminalId = map['terminalId'];
transactionBean.operationDay = map['operationDay'];
transactionBean.transactionNumber = map['transactionNumber'];
transactionBean.instrumentSpecificData = InstrumentSpecificDataBean.fromMap(map['instrumentSpecificData']);
return transactionBean;
}
Map toJson() =>
{
"terminalId": terminalId,
"operationDay": operationDay,
"transactionNumber": transactionNumber,
"instrumentSpecificData": instrumentSpecificData,
};
}
/// authorizationCode : "000000"
/// rrn : "1234567890"
/// cardholderName : "IVAN IVANOV"
/// maskedPan : "123456******7890"
class InstrumentSpecificDataBean {
String? authorizationCode;
String? rrn;
String? cardholderName;
String? maskedPan;
static InstrumentSpecificDataBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
InstrumentSpecificDataBean instrumentSpecificDataBean = InstrumentSpecificDataBean();
instrumentSpecificDataBean.authorizationCode = map['authorizationCode'];
instrumentSpecificDataBean.rrn = map['rrn'];
instrumentSpecificDataBean.cardholderName = map['cardholderName'];
instrumentSpecificDataBean.maskedPan = map['maskedPan'];
return instrumentSpecificDataBean;
}
Map toJson() =>
{
"authorizationCode": authorizationCode,
"rrn": rrn,
"cardholderName": cardholderName,
"maskedPan": maskedPan,
};
}
/// code : "0"
/// description : "Successfully completed"
/// hostResponse : {"code":"0","description":"Successfully completed"}
class ResultBean {
int? code;
String? description;
HostResponseBean? hostResponse;
ErrorResponseBean? errorData;
ResultBean({this.code, this.description});
static ResultBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
ResultBean resultBean = ResultBean();
resultBean.code = map['code'];
resultBean.description = map['description'];
resultBean.hostResponse = HostResponseBean.fromMap(map['hostResponse']);
resultBean.errorData = ErrorResponseBean.fromMap(map['errorData']);
return resultBean;
}
Map toJson() =>
{
"code": code,
"description": description,
"hostResponse": hostResponse,
"errorData": errorData,
};
}
/// code : "0"
/// description : "Successfully completed"
class HostResponseBean {
String? code;
String? description;
static HostResponseBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
HostResponseBean hostResponseBean = HostResponseBean();
hostResponseBean.code = map['code'];
hostResponseBean.description = map['description'];
return hostResponseBean;
}
Map toJson() =>
{
"code": code,
"description": description,
};
}
class ErrorResponseBean {
int? code;
String? description;
static ErrorResponseBean? fromMap(Map<String, dynamic>? map) {
if (map == null) return null;
ErrorResponseBean errorResponseBean = ErrorResponseBean();
errorResponseBean.code = map['code'];
errorResponseBean.description = map['description'];
return errorResponseBean;
}
Map toJson() =>
{
"code": code,
"description": description,
};
}

View File

@ -0,0 +1,31 @@
class TransactionItem {
final String? cardType;
final String? cardExpireDate;
final String? cardNumber;
final String? transactionType;
final num? amount;
final DateTime? date;
TransactionItem({this.cardType, this.cardExpireDate, this.cardNumber, this.transactionType, this.amount, this.date});
static TransactionItem fromJson(Map<String, dynamic> json) {
return TransactionItem(
cardType: json['cardType'],
cardExpireDate: json['cardExpireDate'],
cardNumber: json['cardNumber'],
transactionType: json['transactionType'],
amount: json['amount'],
date: json['date'] != null
? DateTime.parse(json['date'])
: null,
);
}
Map<String, dynamic> toJson() =>
{
'cardType': cardType,
'cardExpireDate': cardExpireDate,
'cardNumber': cardNumber,
'transactionType': transactionType,
'amount': amount,
'date' : date !=null ? date.toString() : null,
};
}

View File

@ -16,8 +16,8 @@ class User {
email: json['mail'], email: json['mail'],
token: json['api_token'], token: json['api_token'],
fullName: json['fullname'], fullName: json['fullname'],
appCompanyId: json['app_company_id'] as int, appCompanyId: json['app_company_id'] ,
kassaId: json['kassa_id'] as int, kassaId: json['kassa_id'] ,
) )
: null; : null;
} }

View File

@ -1,11 +1,15 @@
const String LoginViewRoute = "LoginView"; const String LoginViewRoute = "LoginView";
const String HomeViewRoute = "HomeView"; const String HomeViewRoute = "HomeView";
const String ImageShowRoute = "ImageShowRoute"; const String ImageShowRoute = "ImageShowRoute";
const String CloseDayShowRoute = "CloseDayShowRoute";
const String PaymentViewRoute = "PaymentView"; const String PaymentViewRoute = "PaymentView";
const String PaymentNfcViewRoute = "PaymentNfcViewRoute";
const String HistoryViewRoute = "HistoryView"; const String HistoryViewRoute = "HistoryView";
const String InfoKkmViewRoute = "InfoKkmViewRoute"; const String InfoKkmViewRoute = "InfoKkmViewRoute";
const String SettingsViewRoute = "SettingsViewRoute"; const String SettingsViewRoute = "SettingsViewRoute";
const String QrViewRoute = "QrViewRoute"; const String QrViewRoute = "QrViewRoute";
const String BankViewRoute = "BankViewRoute";
const String BankSettingViewRoute = "BankSettingViewRoute";
const String SettingsPrinterRoute = "SettingsPrinterRoute"; const String SettingsPrinterRoute = "SettingsPrinterRoute";

View File

@ -1,9 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/views/bank_setting/bank_setting_view.dart';
import 'package:aman_kassa_flutter/views/bank_view/bank_view.dart';
import 'package:aman_kassa_flutter/views/check/image_show_container.dart'; import 'package:aman_kassa_flutter/views/check/image_show_container.dart';
import 'package:aman_kassa_flutter/views/home/home_view.dart'; import "package:aman_kassa_flutter/views/home/home_view_m.dart";
import 'package:aman_kassa_flutter/views/close_day_view/close_day_show_container.dart';
import 'package:aman_kassa_flutter/views/history/history_view.dart'; import 'package:aman_kassa_flutter/views/history/history_view.dart';
import 'package:aman_kassa_flutter/views/info_kkm/info_kkm_view.dart'; import 'package:aman_kassa_flutter/views/info_kkm/info_kkm_view.dart';
import 'package:aman_kassa_flutter/views/payment/payment_view.dart'; import 'package:aman_kassa_flutter/views/payment/payment_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/payment_nfc_view.dart';
import 'package:aman_kassa_flutter/views/qr_view/qr_view.dart'; import 'package:aman_kassa_flutter/views/qr_view/qr_view.dart';
import 'package:aman_kassa_flutter/views/settings/printer/views/PrinterSelect.dart'; import 'package:aman_kassa_flutter/views/settings/printer/views/PrinterSelect.dart';
import 'package:aman_kassa_flutter/views/settings/settings_view.dart'; import 'package:aman_kassa_flutter/views/settings/settings_view.dart';
@ -33,6 +38,12 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name!, routeName: settings.name!,
viewToShow: PaymentView(model: model), viewToShow: PaymentView(model: model),
); );
case PaymentNfcViewRoute:
PaymentModel model = settings.arguments as PaymentModel;
return _getPageRoute(
routeName: settings.name!,
viewToShow: PaymentNfcView(model: model),
);
case HistoryViewRoute: case HistoryViewRoute:
return _getPageRoute( return _getPageRoute(
routeName: settings.name!, routeName: settings.name!,
@ -48,6 +59,16 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name!, routeName: settings.name!,
viewToShow: SettingView(), viewToShow: SettingView(),
); );
case BankViewRoute:
return _getPageRoute(
routeName: settings.name!,
viewToShow: BankView(),
);
case BankSettingViewRoute:
return _getPageRoute(
routeName: settings.name!,
viewToShow: BankSettingView(),
);
case QrViewRoute: case QrViewRoute:
ImageShowModel data = settings.arguments as ImageShowModel; ImageShowModel data = settings.arguments as ImageShowModel;
return _getPageRoute( return _getPageRoute(
@ -81,6 +102,12 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name!, routeName: settings.name!,
viewToShow: PrinterPaperView(), viewToShow: PrinterPaperView(),
); );
case CloseDayShowRoute:
CloseDayData data = settings.arguments as CloseDayData;
return _getPageRoute(
routeName: settings.name!,
viewToShow: CloseDayShowContainer(data),
);
default: default:
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => Scaffold( builder: (_) => Scaffold(

View File

@ -2,9 +2,11 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:aman_kassa_flutter/core/base/base_service.dart'; import 'package:aman_kassa_flutter/core/base/base_service.dart';
import 'package:aman_kassa_flutter/core/models/halyk/halyk_post_session.dart';
import 'package:aman_kassa_flutter/redux/state/user_state.dart'; import 'package:aman_kassa_flutter/redux/state/user_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart'; import 'package:aman_kassa_flutter/redux/store.dart';
import 'package:aman_kassa_flutter/views/login/login_view.dart'; import 'package:aman_kassa_flutter/views/login/login_view.dart';
import 'package:crypto/crypto.dart';
import 'package:device_info/device_info.dart'; import 'package:device_info/device_info.dart';
import 'package:aman_kassa_flutter/core/models/message.dart'; import 'package:aman_kassa_flutter/core/models/message.dart';
import 'package:aman_kassa_flutter/core/models/response.dart'; import 'package:aman_kassa_flutter/core/models/response.dart';
@ -17,12 +19,14 @@ import '../models/auth_response.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
/// The service responsible for networking requests /// The service responsible fworking requests
class ApiService extends BaseService { class ApiService extends BaseService {
static const test_host = 'https://kassa-test.aman.com.kz'; static const test_host = 'https://kassa-test.aman.com.kz';
static const test_endpoint = '$test_host/ru/api/v2'; static const test_endpoint = '$test_host/ru/api/v2';
static const host = 'https://kassa.aman.com.kz'; static const host = 'https://kassa.aman.com.kz';
static const endpoint = '$host/ru/api/v2'; static const endpoint = '$host/ru/api/v2';
static const pos_endpoint = 'https://partner.aman.com.kz/api';
final NavigatorService _navigatorService = locator<NavigatorService>(); final NavigatorService _navigatorService = locator<NavigatorService>();
final DialogService _dialogService = locator<DialogService>(); final DialogService _dialogService = locator<DialogService>();
@ -63,6 +67,18 @@ class ApiService extends BaseService {
return Response.fromJsonDynamic(json.decode(response)); return Response.fromJsonDynamic(json.decode(response));
} }
Future<HalykPosSession> halykPosToken(String token, login, password) async {
String salt = '!=uF:w1N_Salh?1gVSJ#eGfJYHA(wS4D';
String hash = md5.convert(utf8.encode('$login$salt')).toString();
print(hash);
Map<String, String> requestBody = <String, String>{'login': login, 'hash': hash};
//var response = await requestFormData('/halykpos/gettoken', requestBody, bodyEntry: true, posEndPoint: true, statusCheck: false);
var response = await requestFormData('/hb/pos/gettoken', requestBody, bodyEntry: true, posEndPoint: true, statusCheck: false);
print(response);
return HalykPosSession.fromJson(jsonDecode(response));
}
Future<Response<dynamic>> money(String token) async { Future<Response<dynamic>> money(String token) async {
Map<String, String> requestBody = <String, String>{'api_token': token}; Map<String, String> requestBody = <String, String>{'api_token': token};
var response = await requestFormData('/money', requestBody); var response = await requestFormData('/money', requestBody);
@ -124,15 +140,17 @@ class ApiService extends BaseService {
} }
Future<String> requestFormData(String point, Map<String, String> requestBody, { bool statusCheck = true } ) async { Future<String> requestFormData(String point, Map<String, String> requestBody, { bool statusCheck = true, bool bodyEntry = false, bool posEndPoint= false } ) async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
Map<String, String> headers = <String, String>{ Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader: "multipart/form-data", HttpHeaders.contentTypeHeader: bodyEntry ? "application/json" : "multipart/form-data",
HttpHeaders.cacheControlHeader: "no-cache" HttpHeaders.cacheControlHeader: "no-cache"
}; };
if(Platform.isAndroid) { if(Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
headers.addAll(<String, String>{ headers.addAll(<String, String>{
@ -153,14 +171,26 @@ class ApiService extends BaseService {
if(this._test) { if(this._test) {
url = '$test_endpoint$point'; url = '$test_endpoint$point';
} }
if(posEndPoint){
url = '$pos_endpoint$point';
}
var uri = Uri.parse(url); var uri = Uri.parse(url);
var request = http.MultipartRequest('POST', uri)
..headers.addAll(headers)
..fields.addAll(requestBody);
var response = await request.send(); String body;
if(bodyEntry) {
http.Response res = await http.post(uri, body: jsonEncode(requestBody), headers: headers );
body = res.body;
} else {
var request = http.MultipartRequest('POST', uri)
..headers.addAll(headers)
..fields.addAll(requestBody);
var response = await request.send();
body = await response.stream.bytesToString();
}
String body = await response.stream.bytesToString();
if(statusCheck) { //Проверка на авторизованный запрос, необязательный параметр if(statusCheck) { //Проверка на авторизованный запрос, необязательный параметр
Response check = Response.fromJsonDynamic(json.decode(body)); Response check = Response.fromJsonDynamic(json.decode(body));
if (!check.operation && ( [401,402,403,412].contains(check.status) ) ) { if (!check.operation && ( [401,402,403,412].contains(check.status) ) ) {

View File

@ -0,0 +1,143 @@
import 'dart:convert';
import 'package:aman_kassa_flutter/core/base/base_service.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/core/models/halyk/halyk_close_day_dao.dart' as Cd;
import 'package:aman_kassa_flutter/core/models/halyk/halyk_post_session.dart' as Ps;
import 'package:aman_kassa_flutter/core/models/halyk/halyk_response_dao.dart';
import 'package:aman_kassa_flutter/core/models/transaction_item.dart';
import 'package:aman_kassa_flutter/core/services/ApiService.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import '../models/aman_dao.dart';
class BankService extends BaseService {
int sdkVersion = 27;
final ApiService _api = locator<ApiService>();
final MethodChannel _channel = MethodChannel('channel:com.amanKassa/bank');
Future<int> version() async {
String result;
try {
result = await _channel.invokeMethod('version');
} catch (e, stack) {
log.e("BankService", e, stack);
result = '0';
}
log.i(result);
return int.parse(result);
}
Future<Ps.HalykPosSession?> renewToken({required String token, required String login, required String password}) async {
Ps.HalykPosSession? result;
try {
result = await _api.halykPosToken(token, login, password);
} catch (e, stack) {
log.e("BankService", e, stack);
}
return result;
}
Future<Cd.HalykCloseDayDao?> closeDay({ required String token}) async {
try {
String response = await _channel.invokeMethod("closeDay", <String, dynamic>{'token': token });
log.i(response);
Cd.HalykCloseDayDao dao = Cd.HalykCloseDayDao.fromMap(json.decode(response))!;
return dao;
} catch (e, stack) {
log.e("BankService", e, stack);
return new Cd.HalykCloseDayDao(result: Cd.ResultBean(description: 'Ошибка при закрытии дня', code: -1));
}
}
Future<HalykResponse> pay({required double amount, required String token}) async {
try {
double total = amount * 100;
log.i('total: $total, ${total.toInt()}');
String response = await _channel.invokeMethod("pay", <String, dynamic>{'amount': total.toInt(), 'token': token });
log.i(response);
HalykResponse dao = HalykResponse.fromMap(json.decode(response))!;
return dao;
} catch (e, stack) {
log.e("BankService", e, stack);
return new HalykResponse(result: ResultBean(description: 'Ошибка оплаты', code: -1));
}
}
Future<HalykResponse> refund({required double amount, required String token, required int terminalId, required int operDay, required int transNum }) async {
try {
String response = await _channel.invokeMethod("refund", <String, dynamic>{
'amount': amount.toInt(), 'token': token , 'terminalId': terminalId, 'operDay': operDay, 'transNum': transNum
});
HalykResponse dao = HalykResponse.fromMap(json.decode(response))!;
return dao;
} catch (e, stack) {
log.e("BankService", e, stack);
return new HalykResponse(result: ResultBean(description: 'Ошибка при возврате', code: -1));
}
}
Future<HalykResponse> reversal({ required String token, required int terminalId, required int operDay, required int transNum }) async {
try {
String response = await _channel.invokeMethod("reversal", <String, dynamic>{
'token': token , 'terminalId': terminalId, 'operDay': operDay, 'transNum': transNum
});
log.i(response);
HalykResponse dao = HalykResponse.fromMap(json.decode(response))!;
return dao;
} catch (e, stack) {
log.e("BankService", e, stack);
return new HalykResponse(result: ResultBean(description: 'Ошибка при возврате', code: -1));
}
}
CloseDayData closeDayDataConvert(Cd.TransactionsBean transactions) {
final DateFormat formatter = DateFormat('dd.MM.yyyy');
final DateTime now = DateTime.now();
final String formatted = formatter.format(now);
List<Cd.TransactionBean> items = transactions.transaction!;
num totalAmount = 0;
int totalCount = 0;
num paymentAmount = 0;
int paymentCount = 0;
num refundAmount = 0;
int refundCount = 0;
num cancelAmount = 0;
int cancelCount = 0;
for(Cd.TransactionBean item in items) {
if(item.type == 'PAYMENT') {
paymentCount++;
paymentAmount += ( item.amount / 100 );
totalAmount += ( item.amount / 100 );
} else if(item.type == 'REFUND') {
refundCount++;
refundAmount += ( item.amount / 100 );
totalAmount -= ( item.amount / 100 );
} else if(item.type == 'REVERSAL') {
cancelCount++;
cancelAmount += ( item.amount / 100 );
totalAmount -= ( item.amount / 100 );
}
totalCount++;
}
CloseDayData closeDayData = new CloseDayData(
items: items,
title: 'Отчет POS от $formatted',
totalAmount: totalAmount, totalCount: totalCount,
paymentAmount: paymentAmount, paymentCount: paymentCount,
refundAmount: refundAmount, refundCount: refundCount,
cancelAmount: cancelAmount, cancelCount: cancelCount,
);
return closeDayData;
}
}

View File

@ -8,6 +8,7 @@ import 'package:aman_kassa_flutter/core/entity/Service.dart';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart'; import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.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/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_data.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart'; import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/check_item.dart'; import 'package:aman_kassa_flutter/core/models/check_item.dart';
@ -142,6 +143,46 @@ class DataService extends BaseService {
_db.insert(Voucher_tableName, voucher.toMap()); _db.insert(Voucher_tableName, voucher.toMap());
} }
Future<Response<dynamic>?> refundM4Bank(
{
required String token,
required CheckData checkData,
required CardData cardData}) async {
try {
var json = cardData.toJson();
json['transactionType'] = VoucherTypeReturnPay;
checkData.cardData = CardData.fromJson(json);
String data = jsonEncode(checkData.toJson());
log.i('token: $token');
log.i('data: $data');
Response<dynamic> response = await _api.sellReturn(token, data);
log.i('response status: ${response.status}');
log.i('response operation: ${response.operation}');
if (response.status == 200 && response.operation == true) {
User user = Redux.store!.state.userState!.user!;
String check = response.body['check'];
dynamic journal = response.body['journal'];
String url = response.body['link'];
int checkNum = journal['check_num'];
var summ = journal['summ'];
double total = summ != null ? double.parse(summ.toString()) : 0.0;
this.insertVoucher(
user: user,
name: 'Чек №$checkNum',
data: data,
base64Data: check,
total: total,
url: url,
type: VoucherTypeReturnPay);
}
return response;
} catch (e, stack) {
log.e("sellOrReturn", e, stack);
}
return null;
}
Future<Response<dynamic>?> sellOrReturn( Future<Response<dynamic>?> sellOrReturn(
{String? paymentType, {String? paymentType,
String? tradeType, String? tradeType,
@ -149,16 +190,19 @@ class DataService extends BaseService {
required List<ProductDao> kassaItems, required List<ProductDao> kassaItems,
required List<CalcModel> calcItems, required List<CalcModel> calcItems,
required String operationType, required String operationType,
required String mode}) async { required String mode,
required CardData? cardData}) async {
try { try {
String data = ""; String data = "";
if (mode == SettingModeKassa) { if (mode == SettingModeKassa) {
CheckData checkData = _transformProductsToCheckData( CheckData checkData = _transformProductsToCheckData(
paymentType: paymentType, tradeType: tradeType, items: kassaItems); paymentType: paymentType, tradeType: tradeType, items: kassaItems);
checkData.cardData = cardData;
data = jsonEncode(checkData.toJson()); data = jsonEncode(checkData.toJson());
} else if (mode == SettingModeCalc) { } else if (mode == SettingModeCalc) {
CheckData checkData = _transformCalcModelToCheckData( CheckData checkData = _transformCalcModelToCheckData(
paymentType: paymentType, tradeType: tradeType, items: calcItems); paymentType: paymentType, tradeType: tradeType, items: calcItems);
checkData.cardData = cardData;
data = jsonEncode(checkData.toJson()); data = jsonEncode(checkData.toJson());
} }

View File

@ -1,10 +1,9 @@
//general //general
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'dart:io';
import 'package:aman_kassa_flutter/shared/app_colors.dart'; import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -23,6 +22,8 @@ import 'views/start_up/start_up_view.dart';
//main start //main start
void main() async { void main() async {
HttpOverrides.global = MyHttpOverrides();
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides(); HttpOverrides.global = MyHttpOverrides();
//initialize locator //initialize locator
@ -49,6 +50,7 @@ class MyHttpOverrides extends HttpOverrides {
class MainApplication extends StatelessWidget { class MainApplication extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StoreProvider<AppState>( return StoreProvider<AppState>(
store: Redux.store!, store: Redux.store!,
child: ScreenUtilInit( child: ScreenUtilInit(

View File

@ -0,0 +1,26 @@
import 'package:aman_kassa_flutter/core/models/halyk/halyk_post_session.dart';
import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import '../store.dart';
@immutable
class SetBankStateAction {
final BankState bankState;
SetBankStateAction(this.bankState);
}
ThunkAction<AppState> saveData(String login, String password) {
return (Store<AppState> store) async {
store.dispatch(SetBankStateAction(BankState(login: login, password: password)));
};
}
ThunkAction<AppState> setHalykSession(HalykPosSession session) {
return (Store<AppState> store) async {
store.dispatch(SetBankStateAction(BankState(session: session)));
};
}

View File

@ -0,0 +1,7 @@
import 'package:aman_kassa_flutter/redux/actions/bank_actions.dart';
import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
bankReducer(BankState prevState, SetBankStateAction action) {
final payload = action.bankState;
return prevState.copyWith(login: payload.login, password: payload.password, session: payload.session);
}

View File

@ -0,0 +1,48 @@
import 'package:aman_kassa_flutter/core/models/halyk/halyk_post_session.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:meta/meta.dart';
@immutable
class BankState {
final String? login;
final String? password;
final HalykPosSession? session;
BankState({this.login, this.password, this.session,});
//read hive
factory BankState.initial(BankState? payload) {
return BankState(
login: payload?.login,
password: payload?.password,
session: payload?.session
);
}
//write hive
BankState copyWith({
@required login,
@required password,
@required session,
}) {
return BankState(
login: login ?? this.login,
password: password ?? this.password,
session: session ?? this.session
);
}
static BankState? fromJson(dynamic json) {
return json != null
? BankState(
password: json['password'],
login: json['login'],
)
: null;
}
dynamic toJson() {
return {"password": password, "login": login};
}
}

View File

@ -1,20 +1,24 @@
import 'package:aman_kassa_flutter/redux/actions/kassa_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/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/reducers/bank_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/calc_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/calc_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/main_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/main_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/setting_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/setting_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/user_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/user_reducer.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/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart'; import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
import 'package:aman_kassa_flutter/redux/state/setting_state.dart'; import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
import 'package:aman_kassa_flutter/redux/state/user_state.dart'; import 'package:aman_kassa_flutter/redux/state/user_state.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
import 'package:redux_persist_flutter/redux_persist_flutter.dart'; import 'package:redux_persist_flutter/redux_persist_flutter.dart';
import 'package:redux_thunk/redux_thunk.dart'; import 'package:redux_thunk/redux_thunk.dart';
import 'package:redux_persist/redux_persist.dart'; import 'package:redux_persist/redux_persist.dart';
import 'actions/bank_actions.dart';
import 'actions/calc_actions.dart'; import 'actions/calc_actions.dart';
//reducer context //reducer context
@ -35,6 +39,10 @@ AppState appReducer(AppState state, dynamic action) {
/** CalcAction **/ /** CalcAction **/
final nextCalcState = calcReducer(state.calcState!, action); final nextCalcState = calcReducer(state.calcState!, action);
return state.copyWith(calcState: nextCalcState); return state.copyWith(calcState: nextCalcState);
} else if (action is SetBankStateAction) {
/** BankAction **/
final nextBankState = bankReducer(state.bankState!, action);
return state.copyWith(bankState: nextBankState);
} }
return state; return state;
} }
@ -46,12 +54,14 @@ class AppState {
final KassaState? kassaState; final KassaState? kassaState;
final SettingState? settingState; final SettingState? settingState;
final CalcState? calcState; final CalcState? calcState;
final BankState? bankState;
AppState({ AppState({
this.userState, this.userState,
this.kassaState, this.kassaState,
this.settingState, this.settingState,
this.calcState, this.calcState,
this.bankState,
}); });
//stable work //stable work
@ -60,28 +70,32 @@ class AppState {
KassaState? kassaState, KassaState? kassaState,
SettingState? settingState, SettingState? settingState,
CalcState? calcState, CalcState? calcState,
BankState? bankState,
}) { }) {
return AppState( return AppState(
userState: userState ?? this.userState, userState: userState ?? this.userState,
kassaState: kassaState ?? this.kassaState, kassaState: kassaState ?? this.kassaState,
settingState: settingState ?? this.settingState, settingState: settingState ?? this.settingState,
calcState: calcState ?? this.calcState, calcState: calcState ?? this.calcState,
bankState: bankState ?? this.bankState,
); );
} }
static AppState? fromJson(dynamic json){ static AppState? fromJson(dynamic json){
return json !=null return json !=null
? AppState( ? AppState(
settingState: SettingState.fromJson(json['settingState']), settingState: SettingState.fromJson(json['settingState']),
userState: UserState.fromJson(json['userState']), userState: UserState.fromJson(json['userState']),
) bankState: BankState.fromJson(json['bankState']),
)
: null; : null;
} }
dynamic toJson() { dynamic toJson() {
return { return {
"settingState": settingState?.toJson(), "settingState": settingState?.toJson(),
"userState" : userState?.toJson(), "userState": userState?.toJson(),
"bankState": bankState?.toJson(),
}; };
} }
} }
@ -102,24 +116,32 @@ class Redux {
// Create Persistor // Create Persistor
final persist = Persistor<AppState>( final persist = Persistor<AppState>(
storage: FlutterStorage(), // Or use other engines storage: FlutterStorage(), // Or use other engines
serializer: JsonSerializer<AppState>(AppState.fromJson), // Or use other serializers serializer: JsonSerializer<AppState>(
AppState.fromJson), // Or use other serializers
); );
final initialState = await persist.load(); AppState? initialState;
try {
initialState = await persist.load();
} catch (e, stack) {
log.e('message', e, stack);
}
final userStateInitial = UserState.initial(initialState?.userState); final userStateInitial = UserState.initial(initialState?.userState);
final kassaStateInitial = KassaState.initial(); final kassaStateInitial = KassaState.initial();
final settingStateInitial = SettingState.initial(initialState?.settingState); final settingStateInitial = SettingState.initial(initialState?.settingState);
final calcStateInitial = CalcState.initial(); final calcStateInitial = CalcState.initial();
final bankStateInitial = BankState.initial(initialState?.bankState);
_store = Store<AppState>( _store = Store<AppState>(
appReducer, appReducer,
middleware: [thunkMiddleware, persist.createMiddleware() ], middleware: [thunkMiddleware, persist.createMiddleware()],
initialState: AppState( initialState: AppState(
userState: userStateInitial, userState: userStateInitial,
kassaState: kassaStateInitial, kassaState: kassaStateInitial,
settingState: settingStateInitial, settingState: settingStateInitial,
calcState: calcStateInitial), calcState: calcStateInitial,
bankState: bankStateInitial),
); );
} }
} }

View File

@ -4,6 +4,8 @@ const Color backgroundColor = Color.fromRGBO(255, 255, 255, 1);
const Color fillColor = Color.fromRGBO(248, 248, 248, 1); const Color fillColor = Color.fromRGBO(248, 248, 248, 1);
const Color primaryColor = Color.fromRGBO(51, 122, 183, 1); const Color primaryColor = Color.fromRGBO(51, 122, 183, 1);
const Color halykColor = Color.fromRGBO(0, 118, 59, 1);
const Color menuColor = Color.fromRGBO(0, 75, 120, 1); const Color menuColor = Color.fromRGBO(0, 75, 120, 1);
@ -12,6 +14,9 @@ const Color greenColor = Color.fromRGBO(92, 184, 92, 1);
const Color whiteColor = Color.fromRGBO(255, 255, 255, 1); const Color whiteColor = Color.fromRGBO(255, 255, 255, 1);
const Color yellowColor = Color.fromRGBO(250, 175, 0, 1); const Color yellowColor = Color.fromRGBO(250, 175, 0, 1);
const Color purpleColor = Color.fromRGBO(118, 122, 230, 1);
const Color purpleSecondColor = Color.fromRGBO(140, 143, 236, 1);
const Color textColor = Color.fromRGBO(51, 51, 51, 1); const Color textColor = Color.fromRGBO(51, 51, 51, 1);

View File

@ -1,4 +1,8 @@
// Define a function. // Define a function.
import 'dart:convert';
import 'package:crypto/crypto.dart';
void printInteger(int aNumber) { void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console. print('The number is $aNumber.'); // Print to console.
} }
@ -8,4 +12,11 @@ void main() {
String dataMatrix = "00000046208262nZ2qnLHODVFWktT"; String dataMatrix = "00000046208262nZ2qnLHODVFWktT";
String numberText = dataMatrix.replaceAll(RegExp("[a-zA-Z]"), ''); String numberText = dataMatrix.replaceAll(RegExp("[a-zA-Z]"), '');
print(int.parse(numberText)); print(int.parse(numberText));
String salt = '!=uF:w1N_Salh?1gVSJ#eGfJYHA(wS4D';
String hash = md5.convert(utf8.encode('uvaissov@gmail.com$salt')).toString();
print(hash);
String value = "100.0";
print(double.parse(value));
} }

View File

@ -0,0 +1,110 @@
import 'dart:convert';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/aman_dao.dart';
import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/redux/actions/bank_actions.dart';
import 'package:aman_kassa_flutter/redux/state/bank_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:flutter/material.dart';
import 'package:flutter/services.dart';
class BankSettingView extends StatefulWidget {
BankSettingView();
@override
_BankSettingViewState createState() => _BankSettingViewState();
}
class _BankSettingViewState extends State<BankSettingView> {
late TextEditingController _emailController;
late TextEditingController _passwordController;
final BankService _bankService = locator<BankService>();
final DialogService _dialogService = locator<DialogService>();
@override
void initState() {
super.initState();
BankState state = Redux.store!.state.bankState!;
_emailController = new TextEditingController(text: state.login);
_passwordController = new TextEditingController(text: state.password);
//permissions();
}
// Future<void> permissions() async {
// try {
// await _bankService.permissions();
// } on PlatformException {
//
// }
// }
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
void _saveData(BuildContext _context) async {
FocusScope.of(_context).unfocus();
await Redux.store!.dispatch(saveData(_emailController.text, _passwordController.text));
_dialogService.showDialog(description: 'Данные сохранены');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Настройка HalykPos'),
),
body: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 14.0),
child: Column(
children: <Widget>[
verticalSpaceTiny,
Text(
'Необходимо указать почту и пароль для подключения к системе проведения платежей',
style: TextStyle(fontSize: 15.0),
textAlign: TextAlign.center,
),
verticalSpaceTiny,
TextField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'E-Mail', hintText: "Введите адрес почты"),
keyboardType: TextInputType.emailAddress,
),
TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
labelText: 'Пароль', hintText: "Введите пароль"),
),
verticalSpaceMedium,
RaisedButton(
onPressed: () => this._saveData(context),
child: Text(
'Cохранить',
style: TextStyle(color: whiteColor, fontSize: 25.0),
),
color: primaryColor,
padding:
const EdgeInsets.symmetric(vertical: 5.0, horizontal: 20.0),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,262 @@
import 'dart:convert';
import 'package:aman_kassa_flutter/core/models/aman_dao.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BankView extends StatefulWidget {
BankView();
@override
_BankViewState createState() => _BankViewState();
}
class _BankViewState extends State<BankView> {
static const MethodChannel _channel =
MethodChannel('channel:com.amanKassa/bank');
static const MethodChannel _activity =
MethodChannel('channel:com.amanKassa/activity');
String? initValue;
String? connectionValue;
String? authValue;
String? payValue;
String? cancelValue;
String? shutdownValue;
String? versionValue;
String? transactionValue;
String? closeDayValue;
String? getValue;
String? errorValue;
bool loading = false;
@override
void initState() {
super.initState();
//load();
}
initialize() async {
String result = await _channel.invokeMethod('init', <String, dynamic>{
'serverUrl': 'http://195.200.74.83:5000',
});
setState(() {
initValue = result;
});
}
version() async {
String result = await _channel.invokeMethod('version');
setState(() {
versionValue = result;
});
}
transaction() async {
String result = await _channel.invokeMethod('transaction');
setState(() {
transactionValue = result ;
});
}
connect() async {
String result = await _channel.invokeMethod("connection");
setState(() {
connectionValue = result;
});
}
auth() async {
String result = await _channel.invokeMethod("auth",
<String, dynamic>{'login': 'uvaissov@gmail.com', 'password': '8147'});
setState(() {
authValue = result;
});
}
pay() async {
String result;
try {
result =
await _channel.invokeMethod("pay", <String, dynamic>{'amount': 100});
} catch (e) {
result = (e.toString());
}
setState(() {
payValue = result;
});
}
cancel() async {
String result;
try {
result = await _channel.invokeMethod("cancel");
} catch (e) {
result = (e.toString());
}
setState(() {
cancelValue = result;
});
}
shutdown() async {
String result;
try {
result = await _channel.invokeMethod("shutdown");
} catch (e) {
result = (e.toString());
}
setState(() {
shutdownValue = result;
});
}
get() async {
String result;
try {
String response = await _channel.invokeMethod("get");
AmanDao dao = AmanDao.fromJson(json.decode(response));
result = '${dao.data} - ${dao.msg}';
} catch (e) {
result = (e.toString());
}
setState(() {
getValue = result;
});
}
closeDay() async {
String result;
try {
String response = await _channel.invokeMethod("closeDay");
AmanDao dao = AmanDao.fromJson(json.decode(response));
result = '${dao.data} - ${dao.msg}';
} catch (e) {
result = (e.toString());
}
setState(() {
closeDayValue = result;
});
}
error() async {
String result;
try {
String json = await _channel.invokeMethod("error");
dynamic data = JsonDecoder().convert(json);
result = data["msg"];
} catch (e) {
result = (e.toString());
}
setState(() {
errorValue = result;
});
}
activity() async {
String result = await _activity.invokeMethod("start");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Банковская страница'),
),
body: loading
? Container(child: Center(child: CircularProgressIndicator()))
: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 14.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Activity m4Bank'), onPressed: activity),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('version: $versionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Version'), onPressed: version),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('init: $initValue' , overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Init'), onPressed: initialize),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('connection: $connectionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Connect'), onPressed: connect),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('auth: $authValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(child: Text('Auth'), onPressed: auth),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('cancel: $cancelValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(child: Text('Cancel'), onPressed: cancel),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('shutdown: $shutdownValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Shutdown'), onPressed: shutdown),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('transaction: $transactionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Transaction'), onPressed: transaction),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('get: $getValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Get'), onPressed: get),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('error: $errorValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('Error'), onPressed: error),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('error: $closeDayValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(
child: Text('CloseDay'), onPressed: closeDay),
],
),
Text('pay: $payValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
RaisedButton(child: Text('Payment'), onPressed: pay),
],
),
),
),
);
}
}

View File

@ -1,18 +1,29 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.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/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/aman_dao.dart';
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/dialog_models.dart'; import 'package:aman_kassa_flutter/core/models/dialog_models.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/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/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.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/setting_const.dart'; import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:aman_kassa_flutter/redux/state/setting_state.dart'; import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart'; import 'package:aman_kassa_flutter/redux/store.dart';
import 'package:aman_kassa_flutter/shared/app_colors.dart'; import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/shared/ui_helpers.dart'; import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:aman_kassa_flutter/views/settings/printer/PrinterTest.dart'; import 'package:aman_kassa_flutter/views/settings/printer/PrinterTest.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button_icon.dart'; import 'package:aman_kassa_flutter/widgets/fields/busy_button_icon.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart'; import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -22,6 +33,8 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
import 'package:vocsy_esys_flutter_share/vocsy_esys_flutter_share.dart'; import 'package:vocsy_esys_flutter_share/vocsy_esys_flutter_share.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../core/models/aman_dao.dart';
class ImageShowContainer extends StatefulWidget { class ImageShowContainer extends StatefulWidget {
final ImageShowModel showModel; final ImageShowModel showModel;
@ -158,8 +171,10 @@ class ImageShowModel {
final CheckImageModal? data; final CheckImageModal? data;
final String title; final String title;
final String? url; final String? url;
final CardData? cardData;
final Voucher? voucher;
ImageShowModel({this.data, required this.title, this.url}); ImageShowModel({this.data, required this.title, this.url, this.cardData, this.voucher});
} }
class MyFloatingActionButton extends StatefulWidget { class MyFloatingActionButton extends StatefulWidget {
@ -175,13 +190,99 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
bool showFab = true; bool showFab = true;
DialogService _dialog = locator<DialogService>(); DialogService _dialog = locator<DialogService>();
NavigatorService _navigatorService = locator<NavigatorService>(); NavigatorService _navigatorService = locator<NavigatorService>();
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final DataService _dataService = locator<DataService>();
double sheetHeight = 260; double sheetHeight = 260;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return showFab //print(widget.data.cardData.transactionType);
? FloatingActionButton( if (showFab) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (widget.data.cardData?.transactionType == "payment")
FloatingActionButton(
backgroundColor: redColor,
tooltip: 'Отмена',
child: Icon(
Icons.cancel,
color: whiteColor,
),
onPressed: () async {
var today = new DateTime.now();
var yesterday = today.subtract(new Duration(days: 1));
if(Redux.store?.state.userState?.smena?.startedAt == null
|| yesterday.isAfter(Redux.store!.state.userState!.smena!.startedAt!)) {
_dialog.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
try {
await Redux.store!.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> response = await reversalHalykPos(widget.data.cardData!, widget.data.voucher!.total!);
if (response.success == true) {
pressRefund();
} else {
_dialog.showDialog(description: response.msg!);
}
} finally {
await Redux.store!.dispatch(changePinSkipFromSetting(false));
}
_navigatorService.replace(HomeViewRoute);
},
heroTag: null,
)
else
SizedBox(
height: 0,
),
SizedBox(
height: 10,
),
if (widget.data.cardData != null && widget.data.cardData?.transactionType == "payment")
FloatingActionButton(
backgroundColor: redColor,
tooltip: 'Возврат',
child: Icon(
Icons.settings_backup_restore,
color: whiteColor,
),
onPressed: () 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!)) {
_dialog.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
try {
await Redux.store!.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> response = await refundHalykPos(widget.data.cardData!, widget.data.voucher!.total!);
if (response.success == true) {
pressRefund();
} else {
_dialog.showDialog(description: response.msg!);
}
} finally {
await Redux.store!.dispatch(changePinSkipFromSetting(false));
}
},
heroTag: null,
)
else
SizedBox(
height: 0,
),
SizedBox(
height: 10,
),
FloatingActionButton(
child: Icon(Icons.share), child: Icon(Icons.share),
onPressed: () { onPressed: () {
var bottomSheetController = showBottomSheet( var bottomSheetController = showBottomSheet(
@ -191,13 +292,8 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(15)), borderRadius: BorderRadius.all(Radius.circular(15)),
boxShadow: [ boxShadow: [BoxShadow(blurRadius: 10, color: Colors.grey[300]!, spreadRadius: 5)]),
BoxShadow( height: 260,
blurRadius: 10,
color: Colors.grey[300]!,
spreadRadius: 5)
]),
height: sheetHeight,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
verticalSpaceSmall, verticalSpaceSmall,
@ -220,41 +316,80 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
BusyButtonIcon( BusyButtonIcon(
title: 'Поделиться', title: 'Поделиться',
onPressed: shareFile, onPressed: shareFile,
mainColor: redColor, mainColor: yellowColor,
icon: Icons.share, icon: Icons.share,
), ),
], ],
))); )));
showFoatingActionButton(false); showFloatingActionButton(false);
bottomSheetController.closed.then((value) { bottomSheetController.closed.then((value) {
showFoatingActionButton(true); showFloatingActionButton(true);
}); });
}, },
) ),
: Container(); ],
);
} else {
return Container();
}
}
pressRefund() async {
Dialogs.showLoadingDialog(context, _keyLoader);
try {
AppState _state = Redux.store!.state;
String _token = _state.userState!.user!.token!;
CardData _cardData = widget.data.cardData!;
CheckData _checkData = CheckData.fromJson(json.decode(widget.data.voucher!.data!));
Response<dynamic>? response =
await _dataService.refundM4Bank(token: _token, cardData: _cardData, checkData: _checkData);
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();
_dialog.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();
}
} }
void shareFile() async { void shareFile() async {
try { try {
await Share.file('Aman Kassa', 'aman_kassa_check.png', await Share.file('Aman Kassa', 'aman_kassa_check.png', base64Decode(widget.data.data!.base64Data!), 'image/png');
base64Decode(widget.data.data!.base64Data!), 'image/png');
} catch (e) { } catch (e) {
print('error: $e'); print('error: $e');
} }
} }
void qrGenerate() async { void qrGenerate() async {
_navigatorService.push(QrViewRoute, _navigatorService.push(QrViewRoute, arguments: ImageShowModel(url: widget.data.url, title: 'Спасибо за покупку'));
arguments:
ImageShowModel(url: widget.data.url, title: 'Спасибо за покупку'));
} }
void callWhatsApp() async { void callWhatsApp() async {
DialogResponse response = await _dialog.showConfirmationDialogInput( DialogResponse response = await _dialog.showConfirmationDialogInput(
description: 'Номер телефона', description: 'Номер телефона', cancelTitle: 'Отмена', confirmationTitle: 'Отправить', formatType: 'phone');
cancelTitle: 'Отмена',
confirmationTitle: 'Отправить',
formatType: 'phone');
if (response.confirmed) { if (response.confirmed) {
String phoneNumber = response.responseText!; String phoneNumber = response.responseText!;
String msg = "Спасибо за покупку! \r\n ${widget.data.url} "; String msg = "Спасибо за покупку! \r\n ${widget.data.url} ";
@ -274,7 +409,6 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
} }
} }
print(url());
if (await canLaunch(url())) { if (await canLaunch(url())) {
await launch(url()); await launch(url());
} else { } else {
@ -282,7 +416,7 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
} }
} }
void showFoatingActionButton(bool value) { void showFloatingActionButton(bool value) {
setState(() { setState(() {
showFab = value; showFab = value;
}); });

View File

@ -0,0 +1,85 @@
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/core/models/halyk/halyk_close_day_dao.dart';
import 'package:aman_kassa_flutter/core/models/transaction_item.dart';
import 'package:aman_kassa_flutter/shared/shared_styles.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class CloseDayShowContainer extends StatelessWidget {
final CloseDayData data;
DateFormat dateFormat = DateFormat("dd.MM.yyyy HH:mm:ss");
CloseDayShowContainer(this.data);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(data.title ?? 'Отчет: Закрытие дня POS'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Общий итоги', style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 15) ),
Table(
children: [
TableRow(children: [
TableCell(child: Text('Оплат:', style: productTextStyle,)),
TableCell(child: Text('${data.paymentCount}', textAlign: TextAlign.center, style: productTextStyle)),
TableCell(child: Text('${data.paymentAmount} T', textAlign: TextAlign.end, style: productTextStyle)),
]),
TableRow(children: [
TableCell(child: Text('Отмен:', style: productTextStyle,)),
TableCell(child: Text('${data.cancelCount}', textAlign: TextAlign.center, style: productTextStyle)),
TableCell(child: Text('${data.cancelAmount} T', textAlign: TextAlign.end, style: productTextStyle)),
]),
TableRow(children: [
TableCell(child: Text('Возвратов:', style: productTextStyle,)),
TableCell(child: Text('${data.refundCount}', textAlign: TextAlign.center, style: productTextStyle)),
TableCell(child: Text('${data.refundAmount} T', textAlign: TextAlign.end, style: productTextStyle)),
]),
TableRow(children: [
TableCell(child: Text('Итого:', style: productTextStyle,)),
TableCell(child: Text('${data.totalCount}', textAlign: TextAlign.center, style: productTextStyle)),
TableCell(child: Text('${data.totalAmount} T', textAlign: TextAlign.end, style: productTextStyle)),
]),
],
)
],
),
),
Divider(),
Expanded(
child: ListView.separated(
itemCount: data.items?.length ?? 0,
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
itemBuilder: (BuildContext context, int index) {
TransactionBean item = data.items!.elementAt(index);
return ListTile(
title: Text(item.instrumentSpecificData?.maskedPan ?? ''),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if(item.instrumentSpecificData!.cardholderName!=null)
Text(item.instrumentSpecificData!.cardholderName!),
Text('Операционный день № ${item.operationDay?.toString()}'),
],
),
trailing: Text('${item.amount / 100} T'),
);
},
),
),
],
)
);
}
}

View File

@ -3,6 +3,9 @@ import 'dart:convert';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart'; import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.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/check_data.dart';
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/core/route_names.dart'; import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/DbService.dart'; import 'package:aman_kassa_flutter/core/services/DbService.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
@ -65,7 +68,16 @@ class _HistoryViewState extends State<HistoryView> {
}, },
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
Voucher voucher = data[index]; Voucher voucher = data[index];
String? base64Data = voucher.base64Data; CardData? cardData;
CloseDayData? closeDayData;
if( voucher.type == VoucherTypeCloseDayPosReport ) {
closeDayData = CloseDayData.fromJson(json.decode(voucher.data!));
} else if( voucher.data !=null ) {
CheckData checkData = CheckData.fromJson(json.decode(voucher.data!));
cardData = checkData.cardData;
}
String? base64Data = voucher.base64Data;
CheckImageModal checkImageData; CheckImageModal checkImageData;
if(base64Data !=null && base64Data.startsWith('{')){ if(base64Data !=null && base64Data.startsWith('{')){
checkImageData = CheckImageModal.fromJson(jsonDecode(base64Data)); checkImageData = CheckImageModal.fromJson(jsonDecode(base64Data));
@ -74,14 +86,29 @@ class _HistoryViewState extends State<HistoryView> {
} }
return ListTile( return ListTile(
onTap: () { onTap: () {
_navigatorService.push(ImageShowRoute,
arguments: ImageShowModel( if( voucher.type == VoucherTypeCloseDayPosReport ) {
_navigatorService.push(CloseDayShowRoute,
arguments: closeDayData);
} else {
_navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(
data: checkImageData, data: checkImageData,
title: voucher.name!, title: voucher.name ?? '',
url: voucher.url!)); url: voucher.url,
cardData: cardData,
voucher: voucher,
));
}
}, },
title: buildText(voucher), title: buildText(voucher),
subtitle: Text(dateFormat.format(voucher.dateTime!)), subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(dateFormat.format(voucher.dateTime!)),
cardData != null ? Text('${cardData.cardNumber} holder: ${cardData.cardholderName}') : Text(''),
],
),
trailing: Icon(Icons.arrow_right), trailing: Icon(Icons.arrow_right),
leading: voucher.type == VoucherTypePayment leading: voucher.type == VoucherTypePayment
? Icon( ? Icon(
@ -93,6 +120,11 @@ class _HistoryViewState extends State<HistoryView> {
MdiIcons.backupRestore, MdiIcons.backupRestore,
size: 40, size: 40,
) )
: voucher.type == VoucherTypeCloseDayPosReport ?
Icon(
Icons.phonelink_lock_outlined,
size: 40,
)
: Icon( : Icon(
Icons.description, Icons.description,
size: 40, size: 40,

View File

@ -1,22 +1,48 @@
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/choice.dart'; import 'package:aman_kassa_flutter/core/models/choice.dart';
import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/shared/app_colors.dart'; import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
const List<Choice> choices = const <Choice>[ class PopupMenu extends StatefulWidget {
//const Choice(title: 'Обновить номенклатуру', icon: Icons.update, command: 'update'),
//const Choice(title: 'Помощь', icon: Icons.help, command: 'help'),
const Choice(
title: 'Информация о ККМ', icon: Icons.info_outline, command: 'infokkm'),
const Choice(title: 'Настройки', icon: Icons.settings, command: 'settings'),
const Choice(title: 'Принтер', icon: Icons.print, command: 'print'),
const Choice(title: 'Выйти', icon: Icons.exit_to_app, command: 'exit')
];
class PopupMenu extends StatelessWidget {
final void Function(Choice value) onSelectChoice; final void Function(Choice value) onSelectChoice;
PopupMenu({required this.onSelectChoice}); PopupMenu({required this.onSelectChoice});
@override
_PopupMenuState createState() => _PopupMenuState();
}
class _PopupMenuState extends State<PopupMenu> {
BankService _bankService = locator<BankService>();
List<Choice> choices = <Choice>[];
@override
void initState() {
// TODO: implement initState
super.initState();
load();
}
load () async {
int version = await _bankService.version();
List<Choice> _choices = <Choice>[
const Choice(title: 'Информация о ККМ', icon: Icons.info_outline, command: 'infokkm'),
//if (version >= 24 )
// const Choice(title: 'Bank', icon: Icons.text_fields, command: 'bank'),
if (version >= _bankService.sdkVersion )
const Choice(title: 'Настройка HalykPos', icon: Icons.phonelink_lock_outlined, command: 'tap2phone'),
const Choice(title: 'Настройки', icon: Icons.settings, command: 'settings'),
const Choice(title: 'Принтер', icon: Icons.print, command: 'print'),
const Choice(title: 'Выйти', icon: Icons.exit_to_app, command: 'exit')
];
setState(() {
choices= _choices;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenuButton<Choice>( return PopupMenuButton<Choice>(
@ -24,23 +50,16 @@ class PopupMenu extends StatelessWidget {
Icons.more_vert, Icons.more_vert,
color: menuColor, color: menuColor,
), ),
onSelected: onSelectChoice, onSelected: widget.onSelectChoice,
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
return choices.map((Choice choice) { return choices.map((Choice choice) {
return PopupMenuItem<Choice>( return PopupMenuItem<Choice>(
value: choice, value: choice,
child: Row( child: Row(children: <Widget>[
children: <Widget>[ Icon(choice.icon, color: primaryColor,),
Icon( SizedBox(width: 5,),
choice.icon, Text(choice.title)
color: primaryColor, ], ),
),
SizedBox(
width: 5,
),
Text(choice.title)
],
),
); );
}).toList(); }).toList();
}, },

View File

@ -154,6 +154,10 @@ class _HomeViewState extends State<HomeView> with WidgetsBindingObserver {
_navigatorService.push(SettingsViewRoute); _navigatorService.push(SettingsViewRoute);
} else if (choice.command == 'print') { } else if (choice.command == 'print') {
_navigatorService.push(SettingsPrinterRoute); _navigatorService.push(SettingsPrinterRoute);
} else if (choice.command == 'bank') {
_navigatorService.push(BankViewRoute);
} else if (choice.command == 'tap2phone') {
_navigatorService.push(BankSettingViewRoute);
} }
} }
@ -190,8 +194,8 @@ class _HomeViewState extends State<HomeView> with WidgetsBindingObserver {
} }
), ),
bottomNavigationBar: BottomBar( bottomNavigationBar: BottomBar(
pageController: pageController, pageController: pageController,
selectedTabIndex: selectedTabIndex, selectedTabIndex: selectedTabIndex,
), ),
); );
} }

View File

@ -3,12 +3,15 @@ import 'dart:convert';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart'; import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart'; import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/core/models/halyk/halyk_close_day_dao.dart';
import 'package:aman_kassa_flutter/core/models/money.dart'; import 'package:aman_kassa_flutter/core/models/money.dart';
import 'package:aman_kassa_flutter/core/models/response.dart'; import 'package:aman_kassa_flutter/core/models/response.dart';
import 'package:aman_kassa_flutter/core/models/dialog_models.dart'; import 'package:aman_kassa_flutter/core/models/dialog_models.dart';
import 'package:aman_kassa_flutter/core/models/user.dart'; import 'package:aman_kassa_flutter/core/models/user.dart';
import 'package:aman_kassa_flutter/core/route_names.dart'; import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/ApiService.dart'; import 'package:aman_kassa_flutter/core/services/ApiService.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/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.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/core/services/navigator_service.dart';
@ -24,6 +27,7 @@ import 'package:aman_kassa_flutter/widgets/fields/aman_icon_button.dart';
import 'package:aman_kassa_flutter/widgets/fields/aman_icon_button_horizontal.dart'; import 'package:aman_kassa_flutter/widgets/fields/aman_icon_button_horizontal.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart'; import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart'; import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
@ -41,6 +45,7 @@ class _AdditionalTabState extends State<AdditionalTab> {
ApiService _api = locator<ApiService>(); ApiService _api = locator<ApiService>();
NavigatorService _navigator = locator<NavigatorService>(); NavigatorService _navigator = locator<NavigatorService>();
DialogService _dialog = locator<DialogService>(); DialogService _dialog = locator<DialogService>();
final BankService _bankService = locator<BankService>();
DataService _dataService = locator<DataService>(); DataService _dataService = locator<DataService>();
final GlobalKey<State> _keyLoader = new GlobalKey<State>(); final GlobalKey<State> _keyLoader = new GlobalKey<State>();
@ -51,6 +56,7 @@ class _AdditionalTabState extends State<AdditionalTab> {
late bool withdrawalBusy; late bool withdrawalBusy;
late bool xReportBusy; late bool xReportBusy;
late bool updateCatalog; late bool updateCatalog;
late bool isClosePosBusy;
@override @override
void initState() { void initState() {
@ -62,6 +68,7 @@ class _AdditionalTabState extends State<AdditionalTab> {
withdrawalBusy = false; withdrawalBusy = false;
xReportBusy = false; xReportBusy = false;
updateCatalog = false; updateCatalog = false;
isClosePosBusy = false;
} }
void _closeSmena() async { void _closeSmena() async {
@ -214,6 +221,55 @@ class _AdditionalTabState extends State<AdditionalTab> {
} }
} }
void _closeDay() async {
setState(() {
isClosePosBusy = true;
});
int version = await _bankService.version();
if (version < _bankService.sdkVersion ) {
setState(() {
isClosePosBusy = false;
});
_dialog.showDialog(description: 'Функция Tap2Phone доступна c Android версии 8.1');
return;
}
await Redux.store!.dispatch(changePinSkipFromSetting(true));
HalykCloseDayDao? closeDayDao = await closeDayHalykPos();
await Redux.store!.dispatch(changePinSkipFromSetting(false));
log.i(closeDayDao?.toJson());
if (closeDayDao?.result?.code != 0) {
if (closeDayDao!.result?.description != null) {
_dialog.showDialog(description: closeDayDao.result!.description!);
}
setState(() {
isClosePosBusy = false;
});
return;
}
CloseDayData closeDayData = _bankService.closeDayDataConvert(closeDayDao!.transactions!);
User user = Redux.store!.state.userState!.user!;
_dataService.insertVoucher(
user: user,
name: closeDayData.title!,
data: jsonEncode(closeDayData.toJson()),
total: closeDayData.totalAmount!.toDouble(),
type: VoucherTypeCloseDayPosReport);
// _dialog.showDialog(description: 'Закрытие дня: операция прошла успешно!');
setState(() {
isClosePosBusy = false;
});
_navigator.push(CloseDayShowRoute,
arguments: closeDayData);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -261,52 +317,72 @@ class _AdditionalTabState extends State<AdditionalTab> {
verticalSpaceMedium, verticalSpaceMedium,
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0), padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Center( child: Row(
child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: [
Text( Column(
'Денег в кассе:', crossAxisAlignment: CrossAxisAlignment.start,
style: TextStyle(color: primaryColor, fontSize: 15), children: <Widget>[
), Row(
SizedBox( children: [
height: 50, Icon(Icons.money, color: primaryColor),
width: double.infinity, Text(
child: StoreConnector<AppState, Money>( 'Денег в кассе:',
converter: (store) => store.state.userState!.money!, style: TextStyle(color: primaryColor, fontSize: 15),
builder: (_, vm) { ),
if (vm.loading == true) { ],
return Center( ),
child: SizedBox( SizedBox(
width: 30, height: 50,
height: 30, // width: double.infinity,
child: Padding( child: StoreConnector<AppState, Money>(
padding: const EdgeInsets.all(8.0), converter: (store) => store.state.userState!.money!,
child: CircularProgressIndicator( builder: (_, vm) {
strokeWidth: 2, if (vm.loading == true) {
valueColor: new AlwaysStoppedAnimation<Color>( return Center(
primaryColor), child: SizedBox(
width: 30,
height: 30,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
new AlwaysStoppedAnimation<Color>(
primaryColor),
),
),
), ),
);
}
return Center(
child: Text(
vm.total != null
? '${vm.total} тенге'
: 'нет информации',
style: TextStyle(
color: vm.total != null
? primaryColor
: Colors.grey.withOpacity(0.5),
fontSize: 25,
fontWeight: FontWeight.bold),
), ),
), );
); }),
} ),
return Center( ],
child: Text( ),
vm.total != null Container(
? '${vm.total} тенге' child: AmanIconButton(
: 'нет информации', title: 'Обновить',
style: TextStyle( onPressed: _checkMoney,
color: vm.total != null busy: isMoneyCheckBusy,
? primaryColor icon: Icons.replay_circle_filled,
: Colors.grey.withOpacity(0.5), mainColor: primaryColor,
fontSize: 25, ),
fontWeight: FontWeight.bold),
),
);
}),
), ),
], ],
)), ),
), ),
verticalSpaceMedium, verticalSpaceMedium,
Wrap( Wrap(
@ -330,12 +406,19 @@ class _AdditionalTabState extends State<AdditionalTab> {
busy: closeSmenaBusy, busy: closeSmenaBusy,
icon: Icons.lock_outline, icon: Icons.lock_outline,
), ),
// AmanIconButton(
// title: 'Денег в кассе',
// onPressed: _checkMoney,
// busy: isMoneyCheckBusy,
// icon: MdiIcons.walletOutline,
// mainColor: primaryColor,
// ),
AmanIconButton( AmanIconButton(
title: 'Денег в кассе', title: 'Закрыть POS',
onPressed: _checkMoney, onPressed: _closeDay,
busy: isMoneyCheckBusy, busy: isClosePosBusy,
icon: MdiIcons.walletOutline, icon: Icons.phonelink_lock_outlined,
mainColor: primaryColor, mainColor: purpleColor,
), ),
AmanIconButton( AmanIconButton(
title: 'Х Отчет', title: 'Х Отчет',

View File

@ -22,7 +22,8 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
class LoginView extends StatefulWidget { class LoginView extends StatefulWidget {
final LoginModel? loginModel; final LoginModel? loginModel;
LoginView({ this.loginModel});
LoginView({this.loginModel});
@override @override
_LoginViewState createState() => _LoginViewState(); _LoginViewState createState() => _LoginViewState();
@ -68,15 +69,18 @@ class _LoginViewState extends State<LoginView> {
converter: (store) => store.state.userState!, converter: (store) => store.state.userState!,
builder: (context, vm) { builder: (context, vm) {
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
backgroundColor: fillColor, backgroundColor: fillColor,
body: Padding( body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50), padding: const EdgeInsets.symmetric(horizontal: 50),
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
verticalSpaceLarge,
Stack( Stack(
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
children: <Widget>[ children: <Widget>[
@ -140,7 +144,9 @@ class _LoginViewState extends State<LoginView> {
) )
], ],
), ),
)); ),
),
);
}); });
} }
@ -168,8 +174,7 @@ class _LoginViewState extends State<LoginView> {
// print(result.format); // The barcode format (as enum) // print(result.format); // The barcode format (as enum)
// print(result // print(result
// .formatNote); // If a unknown format was scanned this field contains a note // .formatNote); // If a unknown format was scanned this field contains a note
if (result.type == ResultType.Barcode && if (result.type == ResultType.Barcode && result.rawContent.length == 60) {
result.rawContent.length == 60) {
if (result.rawContent.toLowerCase().trim().startsWith('test')) { if (result.rawContent.toLowerCase().trim().startsWith('test')) {
_apiService.test = true; _apiService.test = true;
} else { } else {
@ -199,5 +204,6 @@ class LoginModel {
final String? authType; final String? authType;
final String? login; final String? login;
final String? password; final String? password;
LoginModel({this.authType, this.login, this.password}); LoginModel({this.authType, this.login, this.password});
} }

View File

@ -0,0 +1,158 @@
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/logger.dart';
import 'package:aman_kassa_flutter/core/models/halyk/halyk_close_day_dao.dart'
as Cd;
import 'package:aman_kassa_flutter/core/models/halyk/halyk_response_dao.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/store.dart';
import 'package:logger/logger.dart';
import '../../core/models/aman_dao.dart';
import '../../core/models/card_data.dart';
import '../../core/models/halyk/halyk_post_session.dart';
import '../../core/services/BankService.dart';
import '../../redux/state/bank_state.dart';
BankService _bankService = locator<BankService>();
DialogService _dialogService = locator<DialogService>();
final DataService _dataService = locator<DataService>();
final NavigatorService _navigatorService = locator<NavigatorService>();
Logger log = getLogger('PaymentNfcView');
Future<AmanDao<CardData>> paymentHalykPos(double total) 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!);
if (session == null || session.token == null) {
return sessionDeclineDao(session);
}
//Инициализация
HalykResponse response =
await _bankService.pay(token: session.token!, amount: total);
if (response.result?.code == 0) {
CardData cardData = new CardData(
authorizationCode:
response.transaction?.instrumentSpecificData?.authorizationCode,
cardholderName:
response.transaction?.instrumentSpecificData?.cardholderName,
cardNumber: response.transaction?.instrumentSpecificData?.maskedPan,
operationDay: response.transaction?.operationDay,
transactionNumber: response.transaction?.transactionNumber,
terminalId: response.transaction?.terminalId,
transactionType: 'payment');
return AmanDao<CardData>(
msg: response.result?.description, success: true, data: cardData);
}
return AmanDao<CardData>(
msg: response.result?.errorData != null
? response.result!.errorData!.description
: response.result!.description,
success: false);
}
AmanDao<CardData> sessionDeclineDao(HalykPosSession? session) {
String msg = 'Отказано в доступе к API банка';
if(session!=null && session.result?.Response?.Description != null) {
msg = '${session.result?.Response?.Description} (${session.result?.Response?.Code}) ';
}
return AmanDao<CardData>(success: false, msg: msg);
}
Future<AmanDao<CardData>> refundHalykPos(
CardData refundData, double total) 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!);
if (session == null || session.token == null) {
return sessionDeclineDao(session);
}
HalykResponse response = await _bankService.refund(
token: session.token!,
amount: total,
operDay: refundData.operationDay!,
terminalId: refundData.terminalId!,
transNum: refundData.transactionNumber!);
if (response.result?.code == 0) {
CardData cardData = new CardData(
authorizationCode:
response.transaction?.instrumentSpecificData?.authorizationCode,
cardholderName:
response.transaction?.instrumentSpecificData?.cardholderName,
cardNumber: response.transaction?.instrumentSpecificData?.maskedPan,
operationDay: response.transaction?.operationDay,
transactionNumber: response.transaction?.transactionNumber,
terminalId: response.transaction?.terminalId,
transactionType: 'refund');
return AmanDao<CardData>(
msg: response.result?.description, success: true, data: cardData);
}
return AmanDao<CardData>(
msg: response.result?.errorData != null
? response.result!.errorData!.description
: response.result!.description,
success: false);
}
Future<AmanDao<CardData>> reversalHalykPos(
CardData refundData, double total) 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 ?? '');
if (session == null || session.token == null) {
return sessionDeclineDao(session);
}
log.i(refundData.toJson());
HalykResponse response = await _bankService.reversal(
token: session.token!,
operDay: refundData.operationDay!,
terminalId: refundData.terminalId!,
transNum: refundData.transactionNumber!);
if (response.result?.code == 0) {
CardData cardData = new CardData(
authorizationCode:
response.transaction?.instrumentSpecificData?.authorizationCode,
cardholderName:
response.transaction?.instrumentSpecificData?.cardholderName,
cardNumber: response.transaction?.instrumentSpecificData?.maskedPan,
operationDay: response.transaction?.operationDay,
transactionNumber: response.transaction?.transactionNumber,
terminalId: response.transaction?.terminalId,
transactionType: 'reversal');
return AmanDao<CardData>(
msg: response.result?.description, success: true, data: cardData);
}
return AmanDao<CardData>(
msg: response.result?.errorData != null
? response.result!.errorData!.description
: response.result!.description,
success: false);
}
Future<Cd.HalykCloseDayDao?> closeDayHalykPos() 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 ?? '');
if (session== null || session.token == null) {
return new Cd.HalykCloseDayDao(
result: Cd.ResultBean(
description: 'Отказано в доступе к API банка', code: -1));
}
//Инициализация
Cd.HalykCloseDayDao? response =
await _bankService.closeDay(token: session.token!);
return response;
}

View File

@ -1,19 +1,24 @@
import 'dart:convert'; 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/locator.dart';
import 'package:aman_kassa_flutter/core/models/calc_model.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/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/product_dao.dart';
import 'package:aman_kassa_flutter/core/models/response.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/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/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.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/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/calc_actions.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/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/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/operation_const.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/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/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_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/redux/store.dart';
@ -25,6 +30,12 @@ import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart'; import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.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';
class PaymentView extends StatefulWidget { class PaymentView extends StatefulWidget {
final PaymentModel model; final PaymentModel model;
@ -39,13 +50,26 @@ class _PaymentViewState extends State<PaymentView> {
final GlobalKey<State> _keyLoader = new GlobalKey<State>(); final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final DataService _dataService = locator<DataService>(); final DataService _dataService = locator<DataService>();
final DialogService _dialogService = locator<DialogService>(); final DialogService _dialogService = locator<DialogService>();
BankService _bankService = locator<BankService>();
final NavigatorService _navigatorService = locator<NavigatorService>(); final NavigatorService _navigatorService = locator<NavigatorService>();
late bool isBusy; late bool isBusy;
late bool isBankApiAccess;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
isBusy = false; isBusy = false;
isBankApiAccess = false;
_bankInit();
}
_bankInit() async {
int version = await _bankService.version();
if (version >= _bankService.sdkVersion) {
setState(() {
isBankApiAccess = true;
});
}
} }
@override @override
@ -95,9 +119,10 @@ class _PaymentViewState extends State<PaymentView> {
String dataTitle() => String dataTitle() =>
widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат'; widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат';
String dataText() => widget.model.operationType == OperationTypePay String dataText() =>
? 'К оплате' widget.model.operationType == OperationTypePay
: 'К возврату'; ? 'К оплате'
: 'К возврату';
StoreConnector buildStoreConnector() { StoreConnector buildStoreConnector() {
if (widget.model.mode == SettingModeCalc) { if (widget.model.mode == SettingModeCalc) {
@ -133,42 +158,139 @@ class _PaymentViewState extends State<PaymentView> {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: BusyButton( child: BusyButton(
title: 'Оплатить картой', title: 'Оплатить картой',
onPressed: () { onPressed: () {
pressPayment('card'); pressPayment('card', null);
}, },
mainColor: primaryColor, mainColor: primaryColor,
)), )),
horizontalSpaceSmall, horizontalSpaceSmall,
Expanded( Expanded(
child: BusyButton( child: BusyButton(
title: 'Наличными', title: 'Наличными',
onPressed: () { onPressed: () {
pressPayment('cash'); pressPayment('cash', null);
}, },
mainColor: greenColor, mainColor: greenColor,
)), )),
], ],
), ),
), ),
verticalSpaceLarge, verticalSpaceLarge,
_nfsButtonRender(),
verticalSpaceSmall,
Expanded( Expanded(
child: Container(), child: Container(),
), ),
Container( Container(
child: BusyButton( child: BusyButton(
title: 'Отмена', title: 'Отмена',
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
mainColor: redColor, mainColor: redColor,
)), )),
], ],
), ),
); );
} }
pressPayment(String type) async { 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();
}
return InkWell(
onTap: () 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;
}
try {
await Redux.store!.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> data = await paymentHalykPos(_total);
if (data.success == true) {
pressPayment(widget.model.operationType, data.data);
} else {
_dialogService.showDialog(description: data.msg ?? '');
}
} finally {
await Redux.store!.dispatch(changePinSkipFromSetting(false));
}
},
splashColor: halykColor.withOpacity(0.4),
borderRadius: BorderRadius.circular(10.0),
highlightColor: halykColor.withOpacity(0.1),
child: Container(
width: ScreenUtil().setSp(100.0),
padding: const EdgeInsets.symmetric(vertical: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0)
),
child: Column(
children: [
Container(
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(80.0),
margin: const EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
image: AssetImage('assets/images/halykpos.png'), fit: BoxFit.fitWidth
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(
// MdiIcons.nfc,
// color: halykColor,
// size: ScreenUtil().setSp(20.0),
// ),
// Text('Tap2Phone',style: TextStyle(fontSize: ScreenUtil().setSp(10.0), color: halykColor, fontWeight: FontWeight.bold ),),
// ],
// ),
],
),
),
);
}
);
}
pressPayment(String type, CardData? cardData) async {
setState(() { setState(() {
isBusy = true; isBusy = true;
}); });
@ -190,11 +312,13 @@ class _PaymentViewState extends State<PaymentView> {
operationType: widget.model.operationType, operationType: widget.model.operationType,
tradeType: _tradeType, tradeType: _tradeType,
calcItems: calcItems, calcItems: calcItems,
mode: _mode); mode: _mode,
cardData: cardData
);
setState(() { setState(() {
isBusy = false; isBusy = false;
}); });
if( response != null) { if (response != null) {
if (response.operation) { if (response.operation) {
String message = response.body['message']; String message = response.body['message'];
String check = response.body['check']; String check = response.body['check'];
@ -211,24 +335,26 @@ class _PaymentViewState extends State<PaymentView> {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_navigatorService.pop(); _navigatorService.pop();
_navigatorService.push(ImageShowRoute, _navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(data:new CheckImageModal(base64Data: check, textData: checkText !=null ? jsonEncode(checkText) : null ), title: message, url: url )); arguments: ImageShowModel(data: new CheckImageModal(
} else if (!response.operation && ![401,402,403,412,500].contains(response.status)) { 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(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']); _dialogService.showDialog(description: response.body['message']);
} else if(!response.operation && response.body['message'] != null) { } else if (!response.operation && response.body['message'] != null) {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']); _dialogService.showDialog(description: response.body['message']);
} else { } else {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
} }
} else { } else {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
} }
} catch (e) { } catch (e) {
print(e); print(e);
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
} finally { } finally {
//Navigator.of(context, rootNavigator: true).pop(); //Navigator.of(context, rootNavigator: true).pop();
setState(() { setState(() {
isBusy = false; isBusy = false;
@ -262,5 +388,8 @@ class _PaymentViewState extends State<PaymentView> {
class PaymentModel { class PaymentModel {
String operationType; String operationType;
String mode; String mode;
PaymentModel({required this.mode, required this.operationType}); Voucher? voucher;
CardData? cardData;
PaymentModel({required this.mode, required this.operationType, this.voucher, this.cardData});
} }

View File

@ -0,0 +1,525 @@
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/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/flutter_screenutil.dart';
import 'package:logger/logger.dart';
class PaymentNfcView extends StatefulWidget {
final PaymentModel model;
const PaymentNfcView({Key? key, required 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');
late bool isBusy;
late bool isPhoneScaled;
late 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 (session == null || session.token ==null) {
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'];
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;
});
}
}
@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;
}
}

View File

@ -0,0 +1,49 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ActionView extends StatelessWidget {
final String? acceptText;
final String? declineText;
final void Function()? acceptCallback;
final void Function()? declineCallback;
final bool show;
const ActionView(
{Key? key,
this.acceptText,
this.declineText,
this.acceptCallback,
this.declineCallback,
this.show = false})
: super(key: key);
@override
Widget build(BuildContext context) {
return Positioned(
bottom: ScreenUtil().setSp(100),
left: ScreenUtil().setSp(25),
right: ScreenUtil().setSp(25),
child: AnimatedOpacity(
duration: const Duration(milliseconds: 300),
opacity: show ? 1.0 : 0.0,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: buildContainer()),
));
}
Row buildContainer() {
return Row(
children: <Widget>[
if (acceptCallback !=null && acceptText !=null)
Expanded(child: BusyButton(title: acceptText!, onPressed: acceptCallback!)),
SizedBox(width: 5.0,),
if (declineCallback !=null && declineText !=null)
BusyButton(title: declineText!, onPressed: declineCallback!, mainColor: redColor,)
],
);
}
}

View File

@ -0,0 +1,17 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class BackgroundView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
heightFactor: 1.5,
child: Container(
height: ScreenUtil().setSp(250.0),
width: ScreenUtil().setSp(250.0),
decoration:
BoxDecoration(color: purpleSecondColor, shape: BoxShape.circle),
));
}
}

View File

@ -0,0 +1,42 @@
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class CardView extends StatefulWidget {
final bool show;
const CardView({this.show = false });
@override
_CardViewState createState() => _CardViewState();
}
class _CardViewState extends State<CardView> {
@override
Widget build(BuildContext context) {
return Positioned(
child: AnimatedOpacity(
opacity: widget.show? 1 : 0.0,
duration: Duration(seconds: 1),
child: AnimatedContainer(
height: ScreenUtil().setSp(250),
width: ScreenUtil().setSp(250),
transform: Matrix4.translationValues(widget.show? ScreenUtil().setSp(20.0) : 0.0, widget.show? ScreenUtil().setSp(-20.0) : 0.0, 0)
//..rotateZ(widget.show? -0.2:0.0)
,
duration: const Duration(milliseconds: 1500),
curve: Curves.fastOutSlowIn,
child: Container(
//color: Colors.red.withOpacity(0.1),
//alignment: Alignment.bottomCenter,
child: Image.asset(
'assets/images/card.png',
fit: BoxFit.contain,
),
),
),
),
);
}
}

View File

@ -0,0 +1,22 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class LogoView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Positioned(
bottom: ScreenUtil().setSp(75),
left: ScreenUtil().setSp(25),
right: ScreenUtil().setSp(25),
child: Opacity(
opacity: 0.5,
child: Image.asset(
'assets/images/NBK_Logo.png',
fit: BoxFit.fitHeight,
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(120.0),
),
));
}
}

View File

@ -0,0 +1,203 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
class PhoneView extends StatefulWidget {
final bool scaled;
final int? status;
const PhoneView({this.scaled = false, this.status });
@override
_PhoneViewState createState() => _PhoneViewState();
}
class _PhoneViewState extends State<PhoneView> {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
alignment: Alignment.topCenter,
transform: Matrix4.translationValues(widget.scaled? ScreenUtil().setHeight(120) : 0.0, widget.scaled? ScreenUtil().setHeight(50) : 0.0, 0)
..scale(widget.scaled? ScreenUtil().setSp(0.65) : 1.0)..rotateZ(widget.scaled? ScreenUtil().setSp(-0.2):0.0),
duration: const Duration(milliseconds: 1500),
curve: Curves.fastOutSlowIn,
child: Container(
width: ScreenUtil().setSp(380.0),
height: ScreenUtil().setSp(520.0),
//color: Colors.red.withOpacity(0.1),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
width: ScreenUtil().setSp(210.0),
height: ScreenUtil().setSp(430.0),
decoration: BoxDecoration(
color: Colors.white
),
child: Center(
child: AnimatedSwitcher(child: buildContent(), duration: const Duration( milliseconds: 300),),
),
),
Image.asset(
'assets/images/phone_fit.png',
fit: BoxFit.fitWidth,
width: ScreenUtil().setSp(260.0),
height: ScreenUtil().setSp(500.0),
),
],
),
),
);
}
Widget buildContent() {
if(widget.status == 0){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.timerSand, color: yellowColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Инициализация', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 1){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(80.0),
margin: const EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
image: AssetImage('assets/images/halykpos.png'), fit: BoxFit.fitWidth
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
verticalSpaceSmall,
AutoSizeText('Ожидание карты', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 2){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(80.0),
margin: const EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
image: AssetImage('assets/images/halykpos.png'), fit: BoxFit.fitWidth
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
verticalSpaceSmall,
AutoSizeText('Проверка', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 3){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.checkBold, color: greenColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Оплачено', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 4){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.closeOctagon, color: redColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Ошибка инициализации', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 5){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.closeOctagon, color: redColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Ошибка соединения', style: TextStyle(fontWeight: FontWeight.bold),),
AutoSizeText('попробуйте еще раз', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
if(widget.status == 6){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.closeOctagon, color: redColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Ошибка авторизации', style: TextStyle(fontWeight: FontWeight.bold),),
],
);
}
if(widget.status == 7){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.closeOctagon, color: redColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Ошибка чтения карты', style: TextStyle(fontWeight: FontWeight.bold),),
],
);
}
if(widget.status == 8){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.closeOctagon, color: redColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Ошибка транзакции', style: TextStyle(fontWeight: FontWeight.bold),),
],
);
}
if(widget.status == 9){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MdiIcons.checkBold, color: greenColor,size: ScreenUtil().setSp(90.0),),
verticalSpaceSmall,
AutoSizeText('Возврат транзакции', style: TextStyle(fontWeight: FontWeight.bold),)
],
);
}
return Container();
}
}

View File

@ -0,0 +1,84 @@
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class TextStateView extends StatelessWidget {
final int? status;
final String text;
const TextStateView({Key? key, this.status, this.text = ''}) : super(key: key);
@override
Widget build(BuildContext context) {
return Positioned(
bottom: ScreenUtil().setSp(25),
left: ScreenUtil().setSp(25),
right: ScreenUtil().setSp(25),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: buildAutoSizeText()));
}
AutoSizeText buildAutoSizeText() {
switch(status) {
case 0:
return AutoSizeText(
'Инициализация',
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
break;
case 1:
return AutoSizeText(
'Сканирование',
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
break;
case 2:
return AutoSizeText(
'Проверка данных',
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
break;
case 3:
return AutoSizeText(
'Платеж прошел успешно',
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
break;
case 4:
return AutoSizeText(
'Ошибка',
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
break;
default:
return AutoSizeText(
text,
key: UniqueKey(),
style: TextStyle(
fontSize: ScreenUtil().setSp(25.0),
color: whiteColor),
);
}
}
}

View File

@ -182,6 +182,7 @@ class _SettingPrinterViewState extends State<SettingPrinterView> {
_navigatorService.pop(); _navigatorService.pop();
} }
} else { } else {
_navigatorService.pop(); _navigatorService.pop();
} }
} }