diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6cc7126..16b6b08 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -50,6 +50,7 @@ android {
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
+ multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -62,16 +63,37 @@ android {
}
}
buildTypes {
+// all {
+// buildConfigField ("String[]", "SUPPORTED_DEVICES", collectSupportedDevicesToArray())
+// }
debug {
shrinkResources false
minifyEnabled false
+ useProguard false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ defaultConfig {
+ minSdkVersion 24
+ }
}
release {
- signingConfig signingConfigs.release
shrinkResources 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 {
@@ -79,8 +101,28 @@ flutter {
}
dependencies {
+ //coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
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'
androidTestImplementation 'androidx.test:runner:1.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(",") + '}'
+//}
+
+
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
new file mode 100644
index 0000000..88e52af
--- /dev/null
+++ b/android/app/proguard-rules.pro
@@ -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.** { *; }
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6c9b830..e771add 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,51 +1,62 @@
+
-
+ FlutterApplication and put your custom class here.
+ -->
-
-
-
-
-
+
+ />
+ -->
-
-
+
+
+
-
+
-
+
+
\ No newline at end of file
diff --git a/android/app/src/main/assets/sounds/card_prompt.aac b/android/app/src/main/assets/sounds/card_prompt.aac
new file mode 100644
index 0000000..c97b4f5
Binary files /dev/null and b/android/app/src/main/assets/sounds/card_prompt.aac differ
diff --git a/android/app/src/main/assets/sounds/card_read.wav b/android/app/src/main/assets/sounds/card_read.wav
new file mode 100644
index 0000000..ec84dea
Binary files /dev/null and b/android/app/src/main/assets/sounds/card_read.wav differ
diff --git a/android/app/src/main/assets/sounds/error.wav b/android/app/src/main/assets/sounds/error.wav
new file mode 100644
index 0000000..f224049
Binary files /dev/null and b/android/app/src/main/assets/sounds/error.wav differ
diff --git a/android/app/src/main/java/kz/com/aman/kassa/model/AmanDao.java b/android/app/src/main/java/kz/com/aman/kassa/model/AmanDao.java
new file mode 100644
index 0000000..a72beb2
--- /dev/null
+++ b/android/app/src/main/java/kz/com/aman/kassa/model/AmanDao.java
@@ -0,0 +1,43 @@
+package kz.com.aman.kassa.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AmanDao {
+ private boolean success;
+ private String msg;
+ private E data;
+ private List 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 getRows() {
+ return rows;
+ }
+
+ public void setRows(List rows) {
+ this.rows = rows;
+ }
+}
diff --git a/android/app/src/main/java/kz/com/aman/kassa/model/CardData.java b/android/app/src/main/java/kz/com/aman/kassa/model/CardData.java
new file mode 100644
index 0000000..7961365
--- /dev/null
+++ b/android/app/src/main/java/kz/com/aman/kassa/model/CardData.java
@@ -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;
+ }
+}
diff --git a/android/app/src/main/java/kz/com/aman/kassa/model/TransactionDao.java b/android/app/src/main/java/kz/com/aman/kassa/model/TransactionDao.java
new file mode 100644
index 0000000..5ed9b3e
--- /dev/null
+++ b/android/app/src/main/java/kz/com/aman/kassa/model/TransactionDao.java
@@ -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;
+ }
+}
diff --git a/android/app/src/main/java/kz/com/aman/kassa/plugins/BankNfcPlugins.java b/android/app/src/main/java/kz/com/aman/kassa/plugins/BankNfcPlugins.java
new file mode 100644
index 0000000..9697a81
--- /dev/null
+++ b/android/app/src/main/java/kz/com/aman/kassa/plugins/BankNfcPlugins.java
@@ -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 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 dao = new AmanDao<>();
+// dao.setSuccess(true);
+// dao.setMsg("OK");
+// result.success(gson.toJson(dao));
+// }
+// );
+//
+// }
+//
+// @Override
+// public void onPermissionsDeclined() {
+// AmanDao 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 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 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 dao = new AmanDao<>();
+// dao.setSuccess(changed);
+// dao.setMsg("current currency " + (currentCurrency!=null ? currentCurrency.getLetterCode() : "NULL"));
+// result.success(gson.toJson(dao));
+// } else {
+// AmanDao 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 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 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());
+// }
+ }
+
+
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/kz/com/aman/kassa/MainActivity.kt b/android/app/src/main/kotlin/kz/com/aman/kassa/MainActivity.kt
index 5676e2b..749f4e5 100644
--- a/android/app/src/main/kotlin/kz/com/aman/kassa/MainActivity.kt
+++ b/android/app/src/main/kotlin/kz/com/aman/kassa/MainActivity.kt
@@ -1,83 +1,149 @@
package kz.com.aman.kassa
-import android.content.Context
-import android.content.ContextWrapper
+import android.app.Activity
+import android.content.ComponentName
import android.content.Intent
-import android.content.IntentFilter
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.BatteryManager
-import android.os.Build.VERSION
-import android.os.Build.VERSION_CODES
+import android.os.Build
+import android.widget.Toast
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
+import kz.com.aman.kassa.bank.JsonForExternalCall
+import kz.com.aman.kassa.bank.OperationType
-class MainActivity: FlutterActivity() {
- private val CHANNEL = "samples.flutter.dev/battery"
+class MainActivity : FlutterActivity() {
+ 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) {
- GeneratedPluginRegistrant.registerWith(flutterEngine);
- MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
- // Note: this method is invoked on the main thread.
- call, result ->
- if (call.method == "getBatteryLevel") {
- val batteryLevel = getBatteryLevel()
+ GeneratedPluginRegistrant.registerWith(flutterEngine)
+ //MethodChannel(flutterEngine.dartExecutor.binaryMessenger, BANK_CHANNEL).setMethodCallHandler(BankNfcPlugins(this))
- if (batteryLevel != -1) {
- result.success(batteryLevel)
- } else {
- result.error("UNAVAILABLE", "Battery level not available.", null)
+ MethodChannel(flutterEngine.dartExecutor.binaryMessenger, bankChannel).setMethodCallHandler { call, result ->
+ _result = result
+ when (call.method) {
+ "pay" -> {
+ operationPayment(call)
}
- } else if (call.method == "sendMessage") {
- val batteryLevel = sendMessage()
-
- if (batteryLevel != -1) {
- result.success(batteryLevel)
- } else {
- result.error("UNAVAILABLE", "Battery level not available.", null)
+ "refund" -> {
+ operationRefund(call)
+ }
+ "reversal" -> {
+ operationReversal(call)
+ }
+ "closeDay" -> {
+ operationCloseDay(call)
+ }
+ "version" -> {
+ result.success(Build.VERSION.SDK_INT.toString())
+ }
+ else -> {
+ result.notImplemented()
}
- } else {
- result.notImplemented()
}
}
}
- private fun getBatteryLevel(): Int {
- val batteryLevel: Int
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
- batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
- } 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 getOperationList(call: MethodCall) {
+// val token: String = call.argument("token").toString()
+// val operationParameters = createOperationParameters(token)
+// startOperation(OperationType.OPERATIONS_LIST,
+// JsonForExternalCall.getOperationsListJson(operationParameters.authToken))
+//
+// }
+
+ private fun operationPayment(call: MethodCall) {
+ val token = call.argument("token").toString()
+ var amount: Long = 0
+ if (call.argument("amount") != null) {
+ amount = call.argument("amount")!!.toLong()
}
- println("batteryLevel");
- println(batteryLevel);
- return batteryLevel
+ val operationParameters = createOperationParameters(token)
+ startOperation(OperationType.PAYMENT, JsonForExternalCall.getPaymentCardJson(operationParameters.authToken, amount.toString()))
}
- private fun sendMessage(): Int {
- val packageManager: PackageManager = context.packageManager
- val i = Intent(Intent.ACTION_VIEW)
- try {
- val mobileNo: String = "77774904900" //call.argument("mobileNo")
- val message: String = "Hello world" //call.argument("message")
- //https://wa.me/919167370647?text=Yes%20We'll%20do%20this%20in%20frag4%20inOCW
- println("mobileNo: $mobileNo message: $message")
- 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 operationRefund(call: MethodCall) {
+ val token = call.argument("token").toString()
+ val terminalId = call.argument("terminalId").toString()
+ val operDay = call.argument("operDay").toString()
+ val transNum = call.argument("transNum").toString()
+ val amount = call.argument("amount").toString()
+ val operationParameters = createOperationParameters(token)
+ startOperation(OperationType.REFUND, JsonForExternalCall.getRefundCardJson(operationParameters.authToken, terminalId, operDay, transNum, amount))
}
+
+ private fun operationReversal(call: MethodCall) {
+ val token = call.argument("token").toString()
+ val terminalId = call.argument("terminalId").toString()
+ val operDay = call.argument("operDay").toString()
+ val transNum = call.argument("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("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)
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/kz/com/aman/kassa/bank/ExternalPackage.kt b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/ExternalPackage.kt
new file mode 100644
index 0000000..50acba2
--- /dev/null
+++ b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/ExternalPackage.kt
@@ -0,0 +1,3 @@
+package kz.com.aman.kassa.bank;
+
+data class ExternalPackage(val packageName: String, val activityName: String)
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/kz/com/aman/kassa/bank/JsonForExternalCall.kt b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/JsonForExternalCall.kt
new file mode 100644
index 0000000..6360943
--- /dev/null
+++ b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/JsonForExternalCall.kt
@@ -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"
+// }
+// }
+// }"""
+// }
+
+
+
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/kz/com/aman/kassa/bank/OperationType.kt b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/OperationType.kt
new file mode 100644
index 0000000..ce7b101
--- /dev/null
+++ b/android/app/src/main/kotlin/kz/com/aman/kassa/bank/OperationType.kt
@@ -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")
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_bank.xml b/android/app/src/main/res/layout/activity_bank.xml
new file mode 100644
index 0000000..f554aee
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_bank.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..0d62cea
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,494 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/custom_dialog_list.xml b/android/app/src/main/res/layout/custom_dialog_list.xml
new file mode 100644
index 0000000..644c7bc
--- /dev/null
+++ b/android/app/src/main/res/layout/custom_dialog_list.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/layout_pin.xml b/android/app/src/main/res/layout/layout_pin.xml
new file mode 100644
index 0000000..f7149f3
--- /dev/null
+++ b/android/app/src/main/res/layout/layout_pin.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/layout/list_item.xml b/android/app/src/main/res/layout/list_item.xml
new file mode 100644
index 0000000..dcdc7ce
--- /dev/null
+++ b/android/app/src/main/res/layout/list_item.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..47c8224
--- /dev/null
+++ b/android/app/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 16dp
+ 16dp
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ae45d67
--- /dev/null
+++ b/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,107 @@
+
+ TestAppM4bank
+ Authorize
+ Log Out
+ Change Password
+ Enter Your Login
+ Enter Your Password
+ Enter Old Password
+ Enter New Password
+ Register
+ Enter Reader Code
+ Enter Reader Pin
+ Enter Reader Serial Number
+ http://10.10.0.245:29978
+ http://10.45.49.31:29978
+ http://sbertest.m4bank.ru:21017
+
+ http://185.98.84.231:2000
+
+ Check access
+ Get available operations
+ Set language
+ Check connection
+ Make card payment
+ Get common card data
+ Add additional card reader
+ Get readers info
+ Make cash payment
+ Make alipay payment
+ Make card refund
+ Make card refund with D200
+ Make easy cash refund
+ Make alipay refund
+ Make cash refund
+ Make reversal
+ Make easy reversal
+ Make easy card reversal
+ make Reversal Saved Unsuccessful Operation
+ Make reconciliation
+ Get merchant users
+ Get access PI
+ Close day
+ Write terminal keys
+ Read BarCode
+ Update Dictionary
+
+
+ - Payment
+ - Reversal
+ - Refund
+ - Cash
+ - PartRefund
+ - AddReader
+ - CloseDay
+ - AddPrinter
+ - FuncPrinter
+
+
+
+ - rus
+ - eng
+
+
+ confirm
+ clear
+ cancel
+ Resend receipt
+ Get transaction details
+ Get filter list
+ Activate
+ Add new printer
+ Delete printer
+ Printing fiscal check
+ Printing slip check
+ print template
+ Printing X report
+ Printing Z report
+ Printing full report
+ Printing short report
+ Call external application
+ Send register request
+ Cancel interface
+ Make ecom payment
+ Enter service menu
+ Make reversal last saved operation
+ Get reader information
+ Store version
+ Tracker version
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 0
+ start
+ exit
+ Get license
+ Make reversal last
+ Get current transaction details
+ Complete payment
+ Amount
+
diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..1d85e76
--- /dev/null
+++ b/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ kassa.aman.com.kz
+ kassa.aman.systems
+ partner.aman.com.kz
+ partner.aman.systems
+
+
+
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 1eddda3..88944ab 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -7,8 +7,11 @@ buildscript {
dependencies {
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"
}
+
+
}
allprojects {
@@ -16,6 +19,12 @@ allprojects {
google()
jcenter()
}
+
+ configurations.all {
+ resolutionStrategy {
+ cacheDynamicVersionsFor 2, 'minutes'
+ }
+ }
}
rootProject.buildDir = '../build'
@@ -29,3 +38,10 @@ subprojects {
task clean(type: Delete) {
delete rootProject.buildDir
}
+
+tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
diff --git a/assets/images/NBK_Logo.png b/assets/images/NBK_Logo.png
new file mode 100644
index 0000000..bcb79f8
Binary files /dev/null and b/assets/images/NBK_Logo.png differ
diff --git a/assets/images/bank_layout.jpg b/assets/images/bank_layout.jpg
new file mode 100644
index 0000000..ee06ee3
Binary files /dev/null and b/assets/images/bank_layout.jpg differ
diff --git a/assets/images/card.png b/assets/images/card.png
new file mode 100644
index 0000000..d4351eb
Binary files /dev/null and b/assets/images/card.png differ
diff --git a/assets/images/halyk-bank.png b/assets/images/halyk-bank.png
new file mode 100644
index 0000000..c2f486f
Binary files /dev/null and b/assets/images/halyk-bank.png differ
diff --git a/assets/images/halykpos.png b/assets/images/halykpos.png
new file mode 100644
index 0000000..40b13b4
Binary files /dev/null and b/assets/images/halykpos.png differ
diff --git a/assets/images/phone.png b/assets/images/phone.png
new file mode 100644
index 0000000..89c5fce
Binary files /dev/null and b/assets/images/phone.png differ
diff --git a/assets/images/phone_fit.png b/assets/images/phone_fit.png
new file mode 100644
index 0000000..d2baec9
Binary files /dev/null and b/assets/images/phone_fit.png differ
diff --git a/lib/core/entity/Voucher.dart b/lib/core/entity/Voucher.dart
index 0f52599..4187e64 100644
--- a/lib/core/entity/Voucher.dart
+++ b/lib/core/entity/Voucher.dart
@@ -14,6 +14,7 @@ const String Voucher_columnUrl = 'url';
const String VoucherTypePayment = 'payment';
const String VoucherTypeReturnPay = 'returnPay';
const String VoucherTypeReport = 'report';
+const String VoucherTypeCloseDayPosReport = 'closeDayPosReport';
class Voucher {
int? id;
diff --git a/lib/core/foo_test.dart b/lib/core/foo_test.dart
new file mode 100644
index 0000000..ce37072
--- /dev/null
+++ b/lib/core/foo_test.dart
@@ -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);
+}
\ No newline at end of file
diff --git a/lib/core/locator.dart b/lib/core/locator.dart
index f09757e..682e4c7 100644
--- a/lib/core/locator.dart
+++ b/lib/core/locator.dart
@@ -1,5 +1,6 @@
+import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart';
import '../core/services/DbService.dart';
@@ -32,5 +33,7 @@ class LocatorInjector {
_log.d('Initializing DataService Service');
locator.registerLazySingleton(() => DataService());
+ _log.d('Initializing BankService Service');
+ locator.registerLazySingleton(() => BankService());
}
}
\ No newline at end of file
diff --git a/lib/core/models/aman_dao.dart b/lib/core/models/aman_dao.dart
new file mode 100644
index 0000000..7260879
--- /dev/null
+++ b/lib/core/models/aman_dao.dart
@@ -0,0 +1,17 @@
+class AmanDao {
+ 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 data) {
+ return AmanDao(
+ data: data['data'],
+ msg: data['msg'],
+ success: data['success'],
+ rows: data['rows']);
+ }
+}
diff --git a/lib/core/models/card_data.dart b/lib/core/models/card_data.dart
new file mode 100644
index 0000000..23013fb
--- /dev/null
+++ b/lib/core/models/card_data.dart
@@ -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? 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 toJson() =>
+ {
+ 'transactionNumber': transactionNumber,
+ 'operationDay': operationDay,
+ 'cardNumber': cardNumber,
+ 'cardholderName': cardholderName,
+ 'authorizationCode': authorizationCode,
+ 'terminalId' : terminalId,
+ 'transactionType' : transactionType,
+ };
+}
\ No newline at end of file
diff --git a/lib/core/models/check_data.dart b/lib/core/models/check_data.dart
index 9b9ac02..2566760 100644
--- a/lib/core/models/check_data.dart
+++ b/lib/core/models/check_data.dart
@@ -1,22 +1,26 @@
+import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/check_item.dart';
class CheckData {
final String ?type;
num? card;
final List? items;
- CheckData({this.type, this.card, this.items});
+ CardData? cardData;
+ CheckData({this.type, this.card, this.items, this.cardData});
static CheckData fromJson(Map json) {
return CheckData(
type: json['type'],
card: json['card'],
- items: json['items'],
+ items: (json['items'] as List).map((e) => CheckItem.fromJson(e)).toList(),
+ cardData: CardData.fromJson(json['cardData'])
);
}
Map toJson() =>
{
'type': type,
'card': card,
- 'items': items?.map((e) => e.toJson()).toList()
+ 'items': items?.map((e) => e.toJson()).toList(),
+ 'cardData': cardData?.toJson()
};
}
\ No newline at end of file
diff --git a/lib/core/models/close_day_data.dart b/lib/core/models/close_day_data.dart
new file mode 100644
index 0000000..e0b0378
--- /dev/null
+++ b/lib/core/models/close_day_data.dart
@@ -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? 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 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 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(),
+ };
+}
\ No newline at end of file
diff --git a/lib/core/models/halyk/halyk_close_day_dao.dart b/lib/core/models/halyk/halyk_close_day_dao.dart
new file mode 100644
index 0000000..3d2d12f
--- /dev/null
+++ b/lib/core/models/halyk/halyk_close_day_dao.dart
@@ -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? 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? reconciliationResult;
+
+ static CloseDayResultsBean? fromMap(Map? 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 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? transaction;
+
+ static TransactionsBean? fromMap(Map? 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 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? 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? 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,
+ };
+}
\ No newline at end of file
diff --git a/lib/core/models/halyk/halyk_post_session.dart b/lib/core/models/halyk/halyk_post_session.dart
new file mode 100644
index 0000000..dff0603
--- /dev/null
+++ b/lib/core/models/halyk/halyk_post_session.dart
@@ -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 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? 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? 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,
+ };
+}
diff --git a/lib/core/models/halyk/halyk_response_dao.dart b/lib/core/models/halyk/halyk_response_dao.dart
new file mode 100644
index 0000000..8afdce1
--- /dev/null
+++ b/lib/core/models/halyk/halyk_response_dao.dart
@@ -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? 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? 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? 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? 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? 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? 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,
+ };
+}
\ No newline at end of file
diff --git a/lib/core/models/transaction_item.dart b/lib/core/models/transaction_item.dart
new file mode 100644
index 0000000..685139c
--- /dev/null
+++ b/lib/core/models/transaction_item.dart
@@ -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 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 toJson() =>
+ {
+ 'cardType': cardType,
+ 'cardExpireDate': cardExpireDate,
+ 'cardNumber': cardNumber,
+ 'transactionType': transactionType,
+ 'amount': amount,
+ 'date' : date !=null ? date.toString() : null,
+ };
+}
\ No newline at end of file
diff --git a/lib/core/models/user.dart b/lib/core/models/user.dart
index 9b84289..a9ff67e 100644
--- a/lib/core/models/user.dart
+++ b/lib/core/models/user.dart
@@ -16,8 +16,8 @@ class User {
email: json['mail'],
token: json['api_token'],
fullName: json['fullname'],
- appCompanyId: json['app_company_id'] as int,
- kassaId: json['kassa_id'] as int,
+ appCompanyId: json['app_company_id'] ,
+ kassaId: json['kassa_id'] ,
)
: null;
}
diff --git a/lib/core/route_names.dart b/lib/core/route_names.dart
index 85453bc..4ea3704 100644
--- a/lib/core/route_names.dart
+++ b/lib/core/route_names.dart
@@ -1,11 +1,15 @@
const String LoginViewRoute = "LoginView";
const String HomeViewRoute = "HomeView";
const String ImageShowRoute = "ImageShowRoute";
+const String CloseDayShowRoute = "CloseDayShowRoute";
const String PaymentViewRoute = "PaymentView";
+const String PaymentNfcViewRoute = "PaymentNfcViewRoute";
const String HistoryViewRoute = "HistoryView";
const String InfoKkmViewRoute = "InfoKkmViewRoute";
const String SettingsViewRoute = "SettingsViewRoute";
const String QrViewRoute = "QrViewRoute";
+const String BankViewRoute = "BankViewRoute";
+const String BankSettingViewRoute = "BankSettingViewRoute";
const String SettingsPrinterRoute = "SettingsPrinterRoute";
diff --git a/lib/core/router.dart b/lib/core/router.dart
index c395744..2cd132a 100644
--- a/lib/core/router.dart
+++ b/lib/core/router.dart
@@ -1,9 +1,14 @@
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/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/info_kkm/info_kkm_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/settings/printer/views/PrinterSelect.dart';
import 'package:aman_kassa_flutter/views/settings/settings_view.dart';
@@ -33,6 +38,12 @@ Route generateRoute(RouteSettings settings) {
routeName: settings.name!,
viewToShow: PaymentView(model: model),
);
+ case PaymentNfcViewRoute:
+ PaymentModel model = settings.arguments as PaymentModel;
+ return _getPageRoute(
+ routeName: settings.name!,
+ viewToShow: PaymentNfcView(model: model),
+ );
case HistoryViewRoute:
return _getPageRoute(
routeName: settings.name!,
@@ -48,6 +59,16 @@ Route generateRoute(RouteSettings settings) {
routeName: settings.name!,
viewToShow: SettingView(),
);
+ case BankViewRoute:
+ return _getPageRoute(
+ routeName: settings.name!,
+ viewToShow: BankView(),
+ );
+ case BankSettingViewRoute:
+ return _getPageRoute(
+ routeName: settings.name!,
+ viewToShow: BankSettingView(),
+ );
case QrViewRoute:
ImageShowModel data = settings.arguments as ImageShowModel;
return _getPageRoute(
@@ -81,6 +102,12 @@ Route generateRoute(RouteSettings settings) {
routeName: settings.name!,
viewToShow: PrinterPaperView(),
);
+ case CloseDayShowRoute:
+ CloseDayData data = settings.arguments as CloseDayData;
+ return _getPageRoute(
+ routeName: settings.name!,
+ viewToShow: CloseDayShowContainer(data),
+ );
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
diff --git a/lib/core/services/ApiService.dart b/lib/core/services/ApiService.dart
index d31fd44..5ad3e8c 100644
--- a/lib/core/services/ApiService.dart
+++ b/lib/core/services/ApiService.dart
@@ -2,9 +2,11 @@ import 'dart:convert';
import 'dart:io';
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/store.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:aman_kassa_flutter/core/models/message.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;
-/// The service responsible for networking requests
+/// The service responsible fworking requests
class ApiService extends BaseService {
static const test_host = 'https://kassa-test.aman.com.kz';
static const test_endpoint = '$test_host/ru/api/v2';
static const host = 'https://kassa.aman.com.kz';
static const endpoint = '$host/ru/api/v2';
+
+ static const pos_endpoint = 'https://partner.aman.com.kz/api';
final NavigatorService _navigatorService = locator();
final DialogService _dialogService = locator();
@@ -63,6 +67,18 @@ class ApiService extends BaseService {
return Response.fromJsonDynamic(json.decode(response));
}
+ Future 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 requestBody = {'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> money(String token) async {
Map requestBody = {'api_token': token};
var response = await requestFormData('/money', requestBody);
@@ -124,15 +140,17 @@ class ApiService extends BaseService {
}
- Future requestFormData(String point, Map requestBody, { bool statusCheck = true } ) async {
+ Future requestFormData(String point, Map requestBody, { bool statusCheck = true, bool bodyEntry = false, bool posEndPoint= false } ) async {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
Map headers = {
- HttpHeaders.contentTypeHeader: "multipart/form-data",
+ HttpHeaders.contentTypeHeader: bodyEntry ? "application/json" : "multipart/form-data",
HttpHeaders.cacheControlHeader: "no-cache"
};
+
+
if(Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
headers.addAll({
@@ -153,14 +171,26 @@ class ApiService extends BaseService {
if(this._test) {
url = '$test_endpoint$point';
}
+ if(posEndPoint){
+ url = '$pos_endpoint$point';
+ }
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) { //Проверка на авторизованный запрос, необязательный параметр
Response check = Response.fromJsonDynamic(json.decode(body));
if (!check.operation && ( [401,402,403,412].contains(check.status) ) ) {
diff --git a/lib/core/services/BankService.dart b/lib/core/services/BankService.dart
new file mode 100644
index 0000000..b420d67
--- /dev/null
+++ b/lib/core/services/BankService.dart
@@ -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();
+ final MethodChannel _channel = MethodChannel('channel:com.amanKassa/bank');
+
+
+ Future 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 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 closeDay({ required String token}) async {
+ try {
+ String response = await _channel.invokeMethod("closeDay", {'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 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", {'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 refund({required double amount, required String token, required int terminalId, required int operDay, required int transNum }) async {
+ try {
+ String response = await _channel.invokeMethod("refund", {
+ '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 reversal({ required String token, required int terminalId, required int operDay, required int transNum }) async {
+ try {
+ String response = await _channel.invokeMethod("reversal", {
+ '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 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;
+ }
+
+}
diff --git a/lib/core/services/DataService.dart b/lib/core/services/DataService.dart
index 355685e..d9a0ee2 100644
--- a/lib/core/services/DataService.dart
+++ b/lib/core/services/DataService.dart
@@ -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/locator.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/check_item.dart';
@@ -142,6 +143,46 @@ class DataService extends BaseService {
_db.insert(Voucher_tableName, voucher.toMap());
}
+ Future?> 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 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?> sellOrReturn(
{String? paymentType,
String? tradeType,
@@ -149,16 +190,19 @@ class DataService extends BaseService {
required List kassaItems,
required List calcItems,
required String operationType,
- required String mode}) async {
+ required String mode,
+ required CardData? cardData}) async {
try {
String data = "";
if (mode == SettingModeKassa) {
CheckData checkData = _transformProductsToCheckData(
paymentType: paymentType, tradeType: tradeType, items: kassaItems);
+ checkData.cardData = cardData;
data = jsonEncode(checkData.toJson());
} else if (mode == SettingModeCalc) {
CheckData checkData = _transformCalcModelToCheckData(
paymentType: paymentType, tradeType: tradeType, items: calcItems);
+ checkData.cardData = cardData;
data = jsonEncode(checkData.toJson());
}
diff --git a/lib/main.dart b/lib/main.dart
index 392fa16..2e71ad4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,10 +1,9 @@
//general
+import 'dart:io';
+
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart';
-
-import 'dart:io';
-
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -23,6 +22,8 @@ import 'views/start_up/start_up_view.dart';
//main start
void main() async {
+ HttpOverrides.global = MyHttpOverrides();
+
WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides();
//initialize locator
@@ -49,6 +50,7 @@ class MyHttpOverrides extends HttpOverrides {
class MainApplication extends StatelessWidget {
@override
Widget build(BuildContext context) {
+
return StoreProvider(
store: Redux.store!,
child: ScreenUtilInit(
diff --git a/lib/redux/actions/bank_actions.dart b/lib/redux/actions/bank_actions.dart
new file mode 100644
index 0000000..024c870
--- /dev/null
+++ b/lib/redux/actions/bank_actions.dart
@@ -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 saveData(String login, String password) {
+ return (Store store) async {
+ store.dispatch(SetBankStateAction(BankState(login: login, password: password)));
+ };
+}
+
+ThunkAction setHalykSession(HalykPosSession session) {
+ return (Store store) async {
+ store.dispatch(SetBankStateAction(BankState(session: session)));
+ };
+}
diff --git a/lib/redux/reducers/bank_reducer.dart b/lib/redux/reducers/bank_reducer.dart
new file mode 100644
index 0000000..c881809
--- /dev/null
+++ b/lib/redux/reducers/bank_reducer.dart
@@ -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);
+}
diff --git a/lib/redux/state/bank_state.dart b/lib/redux/state/bank_state.dart
new file mode 100644
index 0000000..6e2c035
--- /dev/null
+++ b/lib/redux/state/bank_state.dart
@@ -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};
+ }
+}
diff --git a/lib/redux/store.dart b/lib/redux/store.dart
index 208f0cc..ac02ed3 100644
--- a/lib/redux/store.dart
+++ b/lib/redux/store.dart
@@ -1,20 +1,24 @@
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/reducers/bank_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/setting_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/kassa_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/views/payment/halyk_pos_service.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:redux_persist_flutter/redux_persist_flutter.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:redux_persist/redux_persist.dart';
+import 'actions/bank_actions.dart';
import 'actions/calc_actions.dart';
//reducer context
@@ -35,6 +39,10 @@ AppState appReducer(AppState state, dynamic action) {
/** CalcAction **/
final nextCalcState = calcReducer(state.calcState!, action);
return state.copyWith(calcState: nextCalcState);
+ } else if (action is SetBankStateAction) {
+ /** BankAction **/
+ final nextBankState = bankReducer(state.bankState!, action);
+ return state.copyWith(bankState: nextBankState);
}
return state;
}
@@ -46,12 +54,14 @@ class AppState {
final KassaState? kassaState;
final SettingState? settingState;
final CalcState? calcState;
+ final BankState? bankState;
AppState({
this.userState,
this.kassaState,
this.settingState,
this.calcState,
+ this.bankState,
});
//stable work
@@ -60,28 +70,32 @@ class AppState {
KassaState? kassaState,
SettingState? settingState,
CalcState? calcState,
+ BankState? bankState,
}) {
return AppState(
userState: userState ?? this.userState,
kassaState: kassaState ?? this.kassaState,
settingState: settingState ?? this.settingState,
calcState: calcState ?? this.calcState,
+ bankState: bankState ?? this.bankState,
);
}
static AppState? fromJson(dynamic json){
return json !=null
? AppState(
- settingState: SettingState.fromJson(json['settingState']),
- userState: UserState.fromJson(json['userState']),
- )
+ settingState: SettingState.fromJson(json['settingState']),
+ userState: UserState.fromJson(json['userState']),
+ bankState: BankState.fromJson(json['bankState']),
+ )
: null;
}
dynamic toJson() {
return {
"settingState": settingState?.toJson(),
- "userState" : userState?.toJson(),
+ "userState": userState?.toJson(),
+ "bankState": bankState?.toJson(),
};
}
}
@@ -102,24 +116,32 @@ class Redux {
// Create Persistor
final persist = Persistor(
storage: FlutterStorage(), // Or use other engines
- serializer: JsonSerializer(AppState.fromJson), // Or use other serializers
+ serializer: JsonSerializer(
+ 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 kassaStateInitial = KassaState.initial();
final settingStateInitial = SettingState.initial(initialState?.settingState);
final calcStateInitial = CalcState.initial();
+ final bankStateInitial = BankState.initial(initialState?.bankState);
_store = Store(
appReducer,
- middleware: [thunkMiddleware, persist.createMiddleware() ],
+ middleware: [thunkMiddleware, persist.createMiddleware()],
initialState: AppState(
userState: userStateInitial,
kassaState: kassaStateInitial,
settingState: settingStateInitial,
- calcState: calcStateInitial),
+ calcState: calcStateInitial,
+ bankState: bankStateInitial),
);
}
}
diff --git a/lib/shared/app_colors.dart b/lib/shared/app_colors.dart
index 060bd65..b20dd93 100644
--- a/lib/shared/app_colors.dart
+++ b/lib/shared/app_colors.dart
@@ -4,6 +4,8 @@ const Color backgroundColor = Color.fromRGBO(255, 255, 255, 1);
const Color fillColor = Color.fromRGBO(248, 248, 248, 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);
@@ -12,6 +14,9 @@ const Color greenColor = Color.fromRGBO(92, 184, 92, 1);
const Color whiteColor = Color.fromRGBO(255, 255, 255, 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);
diff --git a/lib/test/foo.dart b/lib/test/foo.dart
index 47ce671..af26e58 100644
--- a/lib/test/foo.dart
+++ b/lib/test/foo.dart
@@ -1,4 +1,8 @@
// Define a function.
+import 'dart:convert';
+
+import 'package:crypto/crypto.dart';
+
void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
@@ -8,4 +12,11 @@ void main() {
String dataMatrix = "00000046208262nZ2qnLHODVFWktT";
String numberText = dataMatrix.replaceAll(RegExp("[a-zA-Z]"), '');
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));
}
\ No newline at end of file
diff --git a/lib/views/bank_setting/bank_setting_view.dart b/lib/views/bank_setting/bank_setting_view.dart
new file mode 100644
index 0000000..452ace4
--- /dev/null
+++ b/lib/views/bank_setting/bank_setting_view.dart
@@ -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 {
+ late TextEditingController _emailController;
+ late TextEditingController _passwordController;
+ final BankService _bankService = locator();
+ final DialogService _dialogService = locator();
+
+ @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 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: [
+ 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),
+ ),
+
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/views/bank_view/bank_view.dart b/lib/views/bank_view/bank_view.dart
new file mode 100644
index 0000000..4f624d6
--- /dev/null
+++ b/lib/views/bank_view/bank_view.dart
@@ -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 {
+ 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', {
+ '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",
+ {'login': 'uvaissov@gmail.com', 'password': '8147'});
+ setState(() {
+ authValue = result;
+ });
+ }
+
+ pay() async {
+ String result;
+ try {
+ result =
+ await _channel.invokeMethod("pay", {'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: [
+ RaisedButton(
+ child: Text('Activity m4Bank'), onPressed: activity),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('version: $versionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Version'), onPressed: version),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('init: $initValue' , overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Init'), onPressed: initialize),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('connection: $connectionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Connect'), onPressed: connect),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('auth: $authValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(child: Text('Auth'), onPressed: auth),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('cancel: $cancelValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(child: Text('Cancel'), onPressed: cancel),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('shutdown: $shutdownValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Shutdown'), onPressed: shutdown),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('transaction: $transactionValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Transaction'), onPressed: transaction),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('get: $getValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Get'), onPressed: get),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Text('error: $errorValue', overflow: TextOverflow.clip, maxLines: 2, softWrap: false),
+ RaisedButton(
+ child: Text('Error'), onPressed: error),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ 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),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/views/check/image_show_container.dart b/lib/views/check/image_show_container.dart
index fac7e56..e0a1369 100644
--- a/lib/views/check/image_show_container.dart
+++ b/lib/views/check/image_show_container.dart
@@ -1,18 +1,29 @@
import 'dart:convert';
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/models/check_data.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/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/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/state/setting_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart';
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:aman_kassa_flutter/views/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/loader/Dialogs.dart';
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
import 'package:esc_pos_utils/esc_pos_utils.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:url_launcher/url_launcher.dart';
+import '../../core/models/aman_dao.dart';
+
class ImageShowContainer extends StatefulWidget {
final ImageShowModel showModel;
@@ -158,8 +171,10 @@ class ImageShowModel {
final CheckImageModal? data;
final String title;
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 {
@@ -175,13 +190,99 @@ class _MyFloatingActionButtonState extends State {
bool showFab = true;
DialogService _dialog = locator();
NavigatorService _navigatorService = locator();
+ final GlobalKey _keyLoader = new GlobalKey();
+ final DataService _dataService = locator();
double sheetHeight = 260;
+
+
@override
Widget build(BuildContext context) {
- return showFab
- ? FloatingActionButton(
+ //print(widget.data.cardData.transactionType);
+ 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 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 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),
onPressed: () {
var bottomSheetController = showBottomSheet(
@@ -191,13 +292,8 @@ class _MyFloatingActionButtonState extends State {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(15)),
- boxShadow: [
- BoxShadow(
- blurRadius: 10,
- color: Colors.grey[300]!,
- spreadRadius: 5)
- ]),
- height: sheetHeight,
+ boxShadow: [BoxShadow(blurRadius: 10, color: Colors.grey[300]!, spreadRadius: 5)]),
+ height: 260,
child: Column(
children: [
verticalSpaceSmall,
@@ -220,41 +316,80 @@ class _MyFloatingActionButtonState extends State {
BusyButtonIcon(
title: 'Поделиться',
onPressed: shareFile,
- mainColor: redColor,
+ mainColor: yellowColor,
icon: Icons.share,
),
],
)));
- showFoatingActionButton(false);
+ showFloatingActionButton(false);
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? 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 {
try {
- await Share.file('Aman Kassa', 'aman_kassa_check.png',
- base64Decode(widget.data.data!.base64Data!), 'image/png');
+ await Share.file('Aman Kassa', 'aman_kassa_check.png', base64Decode(widget.data.data!.base64Data!), 'image/png');
} catch (e) {
print('error: $e');
}
}
void qrGenerate() async {
- _navigatorService.push(QrViewRoute,
- arguments:
- ImageShowModel(url: widget.data.url, title: 'Спасибо за покупку'));
+ _navigatorService.push(QrViewRoute, arguments: ImageShowModel(url: widget.data.url, title: 'Спасибо за покупку'));
}
void callWhatsApp() async {
DialogResponse response = await _dialog.showConfirmationDialogInput(
- description: 'Номер телефона',
- cancelTitle: 'Отмена',
- confirmationTitle: 'Отправить',
- formatType: 'phone');
+ description: 'Номер телефона', cancelTitle: 'Отмена', confirmationTitle: 'Отправить', formatType: 'phone');
if (response.confirmed) {
String phoneNumber = response.responseText!;
String msg = "Спасибо за покупку! \r\n ${widget.data.url} ";
@@ -274,7 +409,6 @@ class _MyFloatingActionButtonState extends State {
}
}
- print(url());
if (await canLaunch(url())) {
await launch(url());
} else {
@@ -282,7 +416,7 @@ class _MyFloatingActionButtonState extends State {
}
}
- void showFoatingActionButton(bool value) {
+ void showFloatingActionButton(bool value) {
setState(() {
showFab = value;
});
diff --git a/lib/views/close_day_view/close_day_show_container.dart b/lib/views/close_day_view/close_day_show_container.dart
new file mode 100644
index 0000000..fcee5fb
--- /dev/null
+++ b/lib/views/close_day_view/close_day_show_container.dart
@@ -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: [
+ 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'),
+ );
+ },
+ ),
+ ),
+ ],
+ )
+ );
+ }
+}
+
+
diff --git a/lib/views/history/history_view.dart b/lib/views/history/history_view.dart
index 1efd547..bcd83d2 100644
--- a/lib/views/history/history_view.dart
+++ b/lib/views/history/history_view.dart
@@ -3,6 +3,9 @@ import 'dart:convert';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/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/services/DbService.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
@@ -65,7 +68,16 @@ class _HistoryViewState extends State {
},
itemBuilder: (BuildContext context, int 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;
if(base64Data !=null && base64Data.startsWith('{')){
checkImageData = CheckImageModal.fromJson(jsonDecode(base64Data));
@@ -74,14 +86,29 @@ class _HistoryViewState extends State {
}
return ListTile(
onTap: () {
- _navigatorService.push(ImageShowRoute,
- arguments: ImageShowModel(
+
+ if( voucher.type == VoucherTypeCloseDayPosReport ) {
+ _navigatorService.push(CloseDayShowRoute,
+ arguments: closeDayData);
+ } else {
+ _navigatorService.push(ImageShowRoute,
+ arguments: ImageShowModel(
data: checkImageData,
- title: voucher.name!,
- url: voucher.url!));
+ title: voucher.name ?? '',
+ url: voucher.url,
+ cardData: cardData,
+ voucher: 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),
leading: voucher.type == VoucherTypePayment
? Icon(
@@ -93,6 +120,11 @@ class _HistoryViewState extends State {
MdiIcons.backupRestore,
size: 40,
)
+ : voucher.type == VoucherTypeCloseDayPosReport ?
+ Icon(
+ Icons.phonelink_lock_outlined,
+ size: 40,
+ )
: Icon(
Icons.description,
size: 40,
diff --git a/lib/views/home/components/popup_menu.dart b/lib/views/home/components/popup_menu.dart
index f3e095a..bd2a16a 100644
--- a/lib/views/home/components/popup_menu.dart
+++ b/lib/views/home/components/popup_menu.dart
@@ -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/services/BankService.dart';
import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart';
+import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
-const List choices = const [
- //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 StatefulWidget {
-class PopupMenu extends StatelessWidget {
final void Function(Choice value) onSelectChoice;
PopupMenu({required this.onSelectChoice});
+ @override
+ _PopupMenuState createState() => _PopupMenuState();
+}
+
+class _PopupMenuState extends State {
+ BankService _bankService = locator();
+ List choices = [];
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ load();
+ }
+
+ load () async {
+ int version = await _bankService.version();
+
+ List _choices = [
+ 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
Widget build(BuildContext context) {
return PopupMenuButton(
@@ -24,23 +50,16 @@ class PopupMenu extends StatelessWidget {
Icons.more_vert,
color: menuColor,
),
- onSelected: onSelectChoice,
+ onSelected: widget.onSelectChoice,
itemBuilder: (BuildContext context) {
return choices.map((Choice choice) {
return PopupMenuItem(
value: choice,
- child: Row(
- children: [
- Icon(
- choice.icon,
- color: primaryColor,
- ),
- SizedBox(
- width: 5,
- ),
- Text(choice.title)
- ],
- ),
+ child: Row(children: [
+ Icon(choice.icon, color: primaryColor,),
+ SizedBox(width: 5,),
+ Text(choice.title)
+ ], ),
);
}).toList();
},
diff --git a/lib/views/home/home_view.dart b/lib/views/home/home_view_m.dart
similarity index 96%
rename from lib/views/home/home_view.dart
rename to lib/views/home/home_view_m.dart
index 3d2b584..73530a7 100644
--- a/lib/views/home/home_view.dart
+++ b/lib/views/home/home_view_m.dart
@@ -154,6 +154,10 @@ class _HomeViewState extends State with WidgetsBindingObserver {
_navigatorService.push(SettingsViewRoute);
} else if (choice.command == 'print') {
_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 with WidgetsBindingObserver {
}
),
bottomNavigationBar: BottomBar(
- pageController: pageController,
- selectedTabIndex: selectedTabIndex,
+ pageController: pageController,
+ selectedTabIndex: selectedTabIndex,
),
);
}
diff --git a/lib/views/home/tabs/AdditionalTab.dart b/lib/views/home/tabs/AdditionalTab.dart
index 1dd7b50..bf01191 100644
--- a/lib/views/home/tabs/AdditionalTab.dart
+++ b/lib/views/home/tabs/AdditionalTab.dart
@@ -3,12 +3,15 @@ import 'dart:convert';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/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/response.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/route_names.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/dialog_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/busy_button.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_redux/flutter_redux.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
@@ -41,6 +45,7 @@ class _AdditionalTabState extends State {
ApiService _api = locator();
NavigatorService _navigator = locator();
DialogService _dialog = locator();
+ final BankService _bankService = locator();
DataService _dataService = locator();
final GlobalKey _keyLoader = new GlobalKey();
@@ -51,6 +56,7 @@ class _AdditionalTabState extends State {
late bool withdrawalBusy;
late bool xReportBusy;
late bool updateCatalog;
+ late bool isClosePosBusy;
@override
void initState() {
@@ -62,6 +68,7 @@ class _AdditionalTabState extends State {
withdrawalBusy = false;
xReportBusy = false;
updateCatalog = false;
+ isClosePosBusy = false;
}
void _closeSmena() async {
@@ -214,6 +221,55 @@ class _AdditionalTabState extends State {
}
}
+ 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
Widget build(BuildContext context) {
return Container(
@@ -261,52 +317,72 @@ class _AdditionalTabState extends State {
verticalSpaceMedium,
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
- child: Center(
- child: Column(
- children: [
- Text(
- 'Денег в кассе:',
- style: TextStyle(color: primaryColor, fontSize: 15),
- ),
- SizedBox(
- height: 50,
- width: double.infinity,
- child: StoreConnector(
- converter: (store) => store.state.userState!.money!,
- builder: (_, vm) {
- if (vm.loading == true) {
- return Center(
- child: SizedBox(
- width: 30,
- height: 30,
- child: Padding(
- padding: const EdgeInsets.all(8.0),
- child: CircularProgressIndicator(
- strokeWidth: 2,
- valueColor: new AlwaysStoppedAnimation(
- primaryColor),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Icon(Icons.money, color: primaryColor),
+ Text(
+ 'Денег в кассе:',
+ style: TextStyle(color: primaryColor, fontSize: 15),
+ ),
+ ],
+ ),
+ SizedBox(
+ height: 50,
+ // width: double.infinity,
+ child: StoreConnector(
+ converter: (store) => store.state.userState!.money!,
+ builder: (_, vm) {
+ if (vm.loading == true) {
+ return Center(
+ child: SizedBox(
+ width: 30,
+ height: 30,
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: CircularProgressIndicator(
+ strokeWidth: 2,
+ valueColor:
+ new AlwaysStoppedAnimation(
+ 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
- ? '${vm.total} тенге'
- : 'нет информации',
- style: TextStyle(
- color: vm.total != null
- ? primaryColor
- : Colors.grey.withOpacity(0.5),
- fontSize: 25,
- fontWeight: FontWeight.bold),
- ),
- );
- }),
+ );
+ }),
+ ),
+ ],
+ ),
+ Container(
+ child: AmanIconButton(
+ title: 'Обновить',
+ onPressed: _checkMoney,
+ busy: isMoneyCheckBusy,
+ icon: Icons.replay_circle_filled,
+ mainColor: primaryColor,
+ ),
),
],
- )),
+ ),
),
verticalSpaceMedium,
Wrap(
@@ -330,12 +406,19 @@ class _AdditionalTabState extends State {
busy: closeSmenaBusy,
icon: Icons.lock_outline,
),
+ // AmanIconButton(
+ // title: 'Денег в кассе',
+ // onPressed: _checkMoney,
+ // busy: isMoneyCheckBusy,
+ // icon: MdiIcons.walletOutline,
+ // mainColor: primaryColor,
+ // ),
AmanIconButton(
- title: 'Денег в кассе',
- onPressed: _checkMoney,
- busy: isMoneyCheckBusy,
- icon: MdiIcons.walletOutline,
- mainColor: primaryColor,
+ title: 'Закрыть POS',
+ onPressed: _closeDay,
+ busy: isClosePosBusy,
+ icon: Icons.phonelink_lock_outlined,
+ mainColor: purpleColor,
),
AmanIconButton(
title: 'Х Отчет',
diff --git a/lib/views/login/login_view.dart b/lib/views/login/login_view.dart
index 5f3b056..15da58e 100644
--- a/lib/views/login/login_view.dart
+++ b/lib/views/login/login_view.dart
@@ -22,7 +22,8 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
class LoginView extends StatefulWidget {
final LoginModel? loginModel;
- LoginView({ this.loginModel});
+
+ LoginView({this.loginModel});
@override
_LoginViewState createState() => _LoginViewState();
@@ -68,15 +69,18 @@ class _LoginViewState extends State {
converter: (store) => store.state.userState!,
builder: (context, vm) {
return Scaffold(
- key: _scaffoldKey,
- backgroundColor: fillColor,
- body: Padding(
+ key: _scaffoldKey,
+ backgroundColor: fillColor,
+ body: SingleChildScrollView(
+ physics: BouncingScrollPhysics(),
+ child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
+ verticalSpaceLarge,
Stack(
alignment: Alignment.bottomLeft,
children: [
@@ -140,7 +144,9 @@ class _LoginViewState extends State {
)
],
),
- ));
+ ),
+ ),
+ );
});
}
@@ -168,8 +174,7 @@ class _LoginViewState extends State {
// print(result.format); // The barcode format (as enum)
// print(result
// .formatNote); // If a unknown format was scanned this field contains a note
- if (result.type == ResultType.Barcode &&
- result.rawContent.length == 60) {
+ if (result.type == ResultType.Barcode && result.rawContent.length == 60) {
if (result.rawContent.toLowerCase().trim().startsWith('test')) {
_apiService.test = true;
} else {
@@ -199,5 +204,6 @@ class LoginModel {
final String? authType;
final String? login;
final String? password;
+
LoginModel({this.authType, this.login, this.password});
}
diff --git a/lib/views/payment/halyk_pos_service.dart b/lib/views/payment/halyk_pos_service.dart
new file mode 100644
index 0000000..0d91bdb
--- /dev/null
+++ b/lib/views/payment/halyk_pos_service.dart
@@ -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();
+DialogService _dialogService = locator();
+final DataService _dataService = locator();
+final NavigatorService _navigatorService = locator();
+Logger log = getLogger('PaymentNfcView');
+
+Future> 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(
+ msg: response.result?.description, success: true, data: cardData);
+ }
+ return AmanDao(
+ msg: response.result?.errorData != null
+ ? response.result!.errorData!.description
+ : response.result!.description,
+ success: false);
+}
+
+AmanDao 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(success: false, msg: msg);
+}
+
+Future> 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(
+ msg: response.result?.description, success: true, data: cardData);
+ }
+ return AmanDao(
+ msg: response.result?.errorData != null
+ ? response.result!.errorData!.description
+ : response.result!.description,
+ success: false);
+}
+
+Future> 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(
+ msg: response.result?.description, success: true, data: cardData);
+ }
+ return AmanDao(
+ msg: response.result?.errorData != null
+ ? response.result!.errorData!.description
+ : response.result!.description,
+ success: false);
+}
+
+Future 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;
+}
diff --git a/lib/views/payment/payment_view.dart b/lib/views/payment/payment_view.dart
index eca516e..ba11d34 100644
--- a/lib/views/payment/payment_view.dart
+++ b/lib/views/payment/payment_view.dart
@@ -1,19 +1,24 @@
import 'dart:convert';
+import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/calc_model.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
+import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/product_dao.dart';
import 'package:aman_kassa_flutter/core/models/response.dart';
import 'package:aman_kassa_flutter/core/route_names.dart';
+import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/calc_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart';
+import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/operation_const.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
+import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
import 'package:aman_kassa_flutter/redux/state/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart';
@@ -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:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
+
+import '../../core/models/aman_dao.dart';
+import '../../core/models/card_data.dart';
+import '../../core/models/card_data.dart';
class PaymentView extends StatefulWidget {
final PaymentModel model;
@@ -39,13 +50,26 @@ class _PaymentViewState extends State {
final GlobalKey _keyLoader = new GlobalKey();
final DataService _dataService = locator();
final DialogService _dialogService = locator();
+ BankService _bankService = locator();
final NavigatorService _navigatorService = locator();
late bool isBusy;
+ late bool isBankApiAccess;
@override
void initState() {
super.initState();
isBusy = false;
+ isBankApiAccess = false;
+ _bankInit();
+ }
+
+ _bankInit() async {
+ int version = await _bankService.version();
+ if (version >= _bankService.sdkVersion) {
+ setState(() {
+ isBankApiAccess = true;
+ });
+ }
}
@override
@@ -95,9 +119,10 @@ class _PaymentViewState extends State {
String dataTitle() =>
widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат';
- String dataText() => widget.model.operationType == OperationTypePay
- ? 'К оплате'
- : 'К возврату';
+ String dataText() =>
+ widget.model.operationType == OperationTypePay
+ ? 'К оплате'
+ : 'К возврату';
StoreConnector buildStoreConnector() {
if (widget.model.mode == SettingModeCalc) {
@@ -133,42 +158,139 @@ class _PaymentViewState extends State {
children: [
Expanded(
child: BusyButton(
- title: 'Оплатить картой',
- onPressed: () {
- pressPayment('card');
- },
- mainColor: primaryColor,
- )),
+ title: 'Оплатить картой',
+ onPressed: () {
+ pressPayment('card', null);
+ },
+ mainColor: primaryColor,
+ )),
horizontalSpaceSmall,
Expanded(
child: BusyButton(
- title: 'Наличными',
- onPressed: () {
- pressPayment('cash');
- },
- mainColor: greenColor,
- )),
+ title: 'Наличными',
+ onPressed: () {
+ pressPayment('cash', null);
+ },
+ mainColor: greenColor,
+ )),
],
),
),
verticalSpaceLarge,
+ _nfsButtonRender(),
+ verticalSpaceSmall,
Expanded(
child: Container(),
),
Container(
child: BusyButton(
- title: 'Отмена',
- onPressed: () {
- Navigator.pop(context);
- },
- mainColor: redColor,
- )),
+ title: 'Отмена',
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ mainColor: redColor,
+ )),
],
),
);
}
- pressPayment(String type) async {
+ Widget _nfsButtonRender() {
+ if (!isBankApiAccess || widget.model.operationType != OperationTypePay) {
+ return Container();
+ }
+ return StoreConnector(
+ 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 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(() {
isBusy = true;
});
@@ -190,11 +312,13 @@ class _PaymentViewState extends State {
operationType: widget.model.operationType,
tradeType: _tradeType,
calcItems: calcItems,
- mode: _mode);
+ mode: _mode,
+ cardData: cardData
+ );
setState(() {
isBusy = false;
});
- if( response != null) {
+ if (response != null) {
if (response.operation) {
String message = response.body['message'];
String check = response.body['check'];
@@ -211,24 +335,26 @@ class _PaymentViewState extends State {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_navigatorService.pop();
_navigatorService.push(ImageShowRoute,
- arguments: ImageShowModel(data:new CheckImageModal(base64Data: check, textData: checkText !=null ? jsonEncode(checkText) : null ), title: message, url: url ));
- } else if (!response.operation && ![401,402,403,412,500].contains(response.status)) {
+ arguments: ImageShowModel(data: new CheckImageModal(
+ base64Data: check, textData: checkText != null ? jsonEncode(checkText) : null),
+ title: message,
+ url: url));
+ } else if (!response.operation && ![401, 402, 403, 412, 500].contains(response.status)) {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']);
- } else if(!response.operation && response.body['message'] != null) {
+ } else if (!response.operation && response.body['message'] != null) {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']);
- } else {
+ } else {
Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
}
} else {
- Navigator.of(_keyLoader.currentContext!, rootNavigator: true).pop();
+ 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;
@@ -262,5 +388,8 @@ class _PaymentViewState extends State {
class PaymentModel {
String operationType;
String mode;
- PaymentModel({required this.mode, required this.operationType});
+ Voucher? voucher;
+ CardData? cardData;
+
+ PaymentModel({required this.mode, required this.operationType, this.voucher, this.cardData});
}
diff --git a/lib/views/payment_nfc/payment_nfc_view.dart b/lib/views/payment_nfc/payment_nfc_view.dart
new file mode 100644
index 0000000..74b82aa
--- /dev/null
+++ b/lib/views/payment_nfc/payment_nfc_view.dart
@@ -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 {
+ final GlobalKey _keyLoader = new GlobalKey();
+ BankService _bankService = locator();
+ DialogService _dialogService = locator();
+ final DataService _dataService = locator();
+ final NavigatorService _navigatorService = locator();
+ 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 kassaItems = _state.kassaState!.kassaItems!;
+ List calcItems = _state.calcState!.calcItems!;
+ Response? 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: [
+ Text(
+ dataText(),
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: whiteColor.withOpacity(0.7),
+ fontSize: ScreenUtil().setSp(15.0)),
+ ),
+ buildStoreConnector(),
+ Expanded(
+ child: Stack(
+ children: [
+ 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(
+ 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(
+ converter: (store) => store.state.kassaState!,
+ builder: (_, vm) {
+ return Text('${widget.model.voucher?.total} тнг',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: whiteColor,
+ fontSize: 35));
+ });
+ }
+ return StoreConnector(
+ converter: (store) => store.state.kassaState!,
+ builder: (_, vm) {
+ return Text('${totalKassa(vm.kassaItems!)} тнг',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: whiteColor,
+ fontSize: 35));
+ });
+ }
+
+ num totalKassa(List kassaItems) {
+ num total = 0.0;
+ kassaItems.forEach((element) {
+ total += element.total == null ? 0.0 : element.total.toDouble();
+ });
+ return total;
+ }
+
+ num totalCalc(List 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;
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/action_view.dart b/lib/views/payment_nfc/widgets/action_view.dart
new file mode 100644
index 0000000..b7f8930
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/action_view.dart
@@ -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: [
+ 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,)
+ ],
+ );
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/background_view.dart b/lib/views/payment_nfc/widgets/background_view.dart
new file mode 100644
index 0000000..be5cf23
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/background_view.dart
@@ -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),
+ ));
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/card_view.dart b/lib/views/payment_nfc/widgets/card_view.dart
new file mode 100644
index 0000000..618c8a6
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/card_view.dart
@@ -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 {
+ @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,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/logo_view.dart b/lib/views/payment_nfc/widgets/logo_view.dart
new file mode 100644
index 0000000..cb926b0
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/logo_view.dart
@@ -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),
+ ),
+ ));
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/phone_view.dart b/lib/views/payment_nfc/widgets/phone_view.dart
new file mode 100644
index 0000000..b29f4e1
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/phone_view.dart
@@ -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 {
+ @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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ 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: [
+ Icon(MdiIcons.checkBold, color: greenColor,size: ScreenUtil().setSp(90.0),),
+ verticalSpaceSmall,
+ AutoSizeText('Возврат транзакции', style: TextStyle(fontWeight: FontWeight.bold),)
+ ],
+ );
+ }
+
+ return Container();
+ }
+}
diff --git a/lib/views/payment_nfc/widgets/text_state.dart b/lib/views/payment_nfc/widgets/text_state.dart
new file mode 100644
index 0000000..f832cfc
--- /dev/null
+++ b/lib/views/payment_nfc/widgets/text_state.dart
@@ -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),
+ );
+ }
+
+
+
+ }
+}
diff --git a/lib/views/settings/setting_printer_view.dart b/lib/views/settings/setting_printer_view.dart
index 92e7d79..5e65b2a 100644
--- a/lib/views/settings/setting_printer_view.dart
+++ b/lib/views/settings/setting_printer_view.dart
@@ -182,6 +182,7 @@ class _SettingPrinterViewState extends State {
_navigatorService.pop();
}
} else {
+
_navigatorService.pop();
}
}