Compare commits

..

95 Commits

Author SHA1 Message Date
error500 fe9e9c5fe4 Merge branch 'master' into backend_nfc
# Conflicts:
#	android/app/src/main/AndroidManifest.xml
#	lib/views/settings/setting_printer_view.dart
#	pubspec.lock
#	pubspec.yaml
2021-12-02 11:18:15 +06:00
error500 7e7fa11623 test url setted 2021-12-02 10:12:41 +06:00
error500 12040f4c2a 1.2.3+36 fix ssl for 5.0 sdk 21 2021-10-12 09:29:13 +06:00
error500 0fe16b5ac9 and fix printer permissions 2021-10-11 17:12:53 +06:00
error500 1dd045a4d9 fix_ssl_master 2021-10-11 13:12:19 +06:00
error500 f34080dc6b fix version 2021-10-11 11:37:53 +06:00
error500 85af519d77 and android trusted domain
disable ssl on dart
2021-10-05 11:58:01 +06:00
error500 7638d5391c locationAlways disable 2021-10-01 09:15:36 +06:00
error500 40efff3fb7 location problem android permissions 2021-09-23 14:56:02 +06:00
error500 9bb4c47249 usesCleartextTraffic = false
gettoken change to prod
2021-09-08 12:48:25 +06:00
error500 583b7b74e9 permission fix 2021-08-31 13:31:23 +06:00
error500 1c7730bf2e 1.2.3+30 android 2021-08-31 10:44:45 +06:00
suvaissov b05251e920 bank release ui fix 2021-07-14 15:25:43 +06:00
suvaissov 33897977a8 halyk token decline response parse 2021-06-25 14:09:21 +06:00
suvaissov cb6e68bb1e Merge branch 'master' into backend_nfc
# Conflicts:
#	lib/views/home/tabs/AdditionalTab.dart
2021-06-21 09:25:52 +06:00
suvaissov b23c505fc5 reversal release 2021-06-08 16:23:27 +06:00
suvaissov f4ce7b85b9 refund fix 2021-06-08 13:45:18 +06:00
Serik Uvaissov a9ce27cbb1 ios build 1.2.3 2021-05-31 15:10:02 +06:00
suvaissov 32100a3ecb XReport fix 2021-05-31 14:17:57 +06:00
suvaissov 77ed845505 Bottom Draggable Sheet fix to PageBuilder 2021-05-31 13:59:41 +06:00
Serik Uvaissov 7544788744 ios build 1.2.2 2021-05-28 09:39:42 +06:00
suvaissov a5dd1dac5f andorid release 2021-05-27 20:53:24 +06:00
suvaissov 9cea8b445b pin code check fixes 2021-05-27 13:09:22 +06:00
suvaissov 5a1f086d78 bug fixes on halyk payment 2021-05-26 15:47:24 +06:00
suvaissov c497fa7ed6 for halykpos service minsdk 27 2021-05-26 14:14:42 +06:00
suvaissov 51b531c129 change gettoken api url 2021-05-26 13:23:44 +06:00
suvaissov 27d0d6d11d Merge branch 'master' into backend_nfc
# Conflicts:
#	pubspec.yaml
2021-05-26 12:41:59 +06:00
suvaissov 760fc63da0 confirm on location permissions 2021-05-26 12:21:45 +06:00
suvaissov f45835d215 printer android fix 2021-05-19 12:11:39 +06:00
suvaissov 0de81ff7d2 uses permission access 2021-05-05 13:37:11 +06:00
suvaissov 07fa2d683a payment, refund, closeday - finished/ Tested with moscow server 2021-04-27 14:14:21 +06:00
suvaissov 9d54a20f65 payment +
closeDay +-
refund -
2021-04-27 11:18:17 +06:00
suvaissov 93e6163ef2 Merge branch 'master' into backend_nfc
# Conflicts:
#	android/app/build.gradle
2021-04-26 15:07:33 +06:00
suvaissov 881c96f620 andoird print samsung? but not work china devices 2021-04-26 15:04:46 +06:00
suvaissov fb1f030fb1 bank fix 2021-04-20 19:55:38 +06:00
suvaissov f09dba0b54 Merge branch 'master' into backend_nfc 2021-04-20 12:09:55 +06:00
suvaissov 7a50652eda change button colors 2021-04-20 12:09:23 +06:00
suvaissov fb63b8acb2 api start 2021-04-19 16:47:33 +06:00
Serik Uvaissov 09062fb8a3 ios build 2021-04-15 10:14:01 +06:00
suvaissov 228ffd1400 no bug bank 2021-03-30 13:56:49 +06:00
suvaissov 6d385d16e8 clean bank 2021-03-30 13:45:21 +06:00
suvaissov 2a3519500e last fixes after merge @printer and @pin_locker 2021-03-30 09:54:27 +06:00
suvaissov 0cfbd11ade Merge branch 'master' into pin_locker
# Conflicts:
#	lib/core/router.dart
#	lib/redux/actions/setting_actions.dart
#	lib/redux/reducers/setting_reducer.dart
#	lib/redux/state/setting_state.dart
#	lib/views/home/components/popup_menu.dart
#	lib/views/home/home_view.dart
#	pubspec.lock
#	pubspec.yaml
2021-03-30 09:42:37 +06:00
suvaissov 8c3451ffd2 printer release 2021-03-17 11:46:30 +06:00
suvaissov a45bbc03c3 print images 2021-03-11 15:48:58 +06:00
suvaissov 54df0728f3 Merge branch 'master' into backend_nfc
# Conflicts:
#	android/app/build.gradle
#	lib/views/home/home_view.dart
#	pubspec.yaml
2021-03-03 17:39:13 +06:00
suvaissov fd4168b614 change target SDK to 29 2021-02-04 19:48:29 +06:00
suvaissov 8a53233afd pin lock? bug fixes 2021-01-20 01:11:21 +06:00
suvaissov e1301e7340 fix crash app 2021-01-19 11:00:19 +06:00
suvaissov 8c0ae9939a pin code in settings 2021-01-19 01:19:13 +06:00
suvaissov 839432d011 pin release 2021-01-19 01:01:58 +06:00
suvaissov 923e32274a fix deprecate methods 2021-01-18 12:47:59 +06:00
suvaissov 50b3694cac pin locker before start 2021-01-18 12:19:55 +06:00
suvaissov e4bf1db47b up depens version 2021-01-18 12:17:47 +06:00
suvaissov f8d7e4717f Merge branch 'master' into backend_nfc
# Conflicts:
#	lib/core/services/DataService.dart
#	lib/views/start_up/start_up_view.dart
#	pubspec.lock
#	pubspec.yaml
2021-01-18 12:16:36 +06:00
suvaissov b31e685af0 - halykpos logo
- save pos close day report
2021-01-14 22:10:53 +06:00
suvaissov 62f107d7ac http://redmine.helios-soft.kz/issues/1791 HalyPos разместить логотип банка при оплате POS 2021-01-12 11:56:53 +06:00
suvaissov a1b8223980 refund and close day release 2021-01-08 14:52:11 +06:00
suvaissov 48398435e8 fix bugs after up dependencies version 2021-01-05 17:12:24 +06:00
suvaissov 0de65ff2e9 refund release 2021-01-05 16:09:12 +06:00
suvaissov 4a1f65c681 close day success
refund start developing
2021-01-02 16:51:08 +06:00
suvaissov f9ed7711e9 halyk test success 2020-12-21 11:21:50 +06:00
suvaissov bc853d5bdd first try halyk connect 2020-12-20 12:22:22 +06:00
suvaissov b22abd1389 Merge branch 'master' into backend_nfc
# Conflicts:
#	lib/redux/store.dart
#	pubspec.lock
#	pubspec.yaml
2020-12-20 10:51:11 +06:00
Serik.Uvaissov 5f4d20fce4 currency release 2020-09-09 22:08:07 +06:00
Serik.Uvaissov b83d8974df build.gradle shring and minify 2020-08-23 18:19:07 +06:00
Serik.Uvaissov e06d192dcb Toast.makeText CardPaymentCallbackHandler
currency method BankNfcPlugins
2020-08-23 16:48:56 +06:00
Serik.Uvaissov 34dc1cb8a2 Toast.makeText remove 2020-08-23 16:44:36 +06:00
Serik.Uvaissov 1f18d5d928 permissions add method MethodCallHandler 2020-08-23 14:37:12 +06:00
Serik.Uvaissov 273aba6ce8 edit card handler
nfc button
2020-08-23 14:19:25 +06:00
Serik.Uvaissov 1b9a8af2c5 ui and back worked 2020-08-23 14:05:56 +06:00
Serik.Uvaissov 8edcc2cdb3 backend nfc release 2020-08-05 09:09:08 +06:00
Serik.Uvaissov e0c4ade930 ui commit and debug fix 2020-08-02 17:07:49 +06:00
Serik.Uvaissov 23774d69dc animation with content 2020-07-30 16:47:42 +06:00
Serik.Uvaissov adc323f383 24 min sdk for debug version 2020-07-23 15:29:43 +06:00
Serik.Uvaissov cb2e5093ca min SDK 24 2020-07-22 10:46:49 +06:00
Serik.Uvaissov 3eb69b1ff2 try - 1 2020-07-22 01:36:45 +06:00
Serik.Uvaissov 4196636df1 gradle crash 2020-07-21 22:56:34 +06:00
Serik.Uvaissov ee598f59d8 payment and cancel release 2020-07-20 18:54:27 +06:00
Serik.Uvaissov e6e2b3516b Merge branch 'master' into nfc-android 2020-07-18 23:46:16 +06:00
Serik.Uvaissov 39153af143 auth m4bank release 2020-07-18 15:54:11 +06:00
Serik.Uvaissov ef10080cd2 add 2020-07-17 21:06:48 +06:00
Serik.Uvaissov 49c3cc5b8d up dependencies version 2020-07-17 20:28:43 +06:00
Serik.Uvaissov c3cf63fdbe start flutter plugin 2020-07-17 01:44:42 +06:00
Serik.Uvaissov b09646b475 Merge branch 'master' into nfc-android 2020-07-16 21:37:39 +06:00
Serik.Uvaissov 72f59553b4 visa valid 2020-07-16 21:35:35 +06:00
Serik.Uvaissov ce8f20b7b0 Merge branch 'master' into nfc-android
# Conflicts:
#	lib/views/login/login_view.dart
#	pubspec.yaml
2020-07-15 13:57:14 +06:00
Serik.Uvaissov f630d1584f merge 2020-07-15 13:55:30 +06:00
Serik.Uvaissov cb7a2765c6 change package name for nfc-android 2020-07-13 13:25:07 +06:00
Serik.Uvaissov 4f9bea7980 Merge branch 'master' into nfc-android
# Conflicts:
#	android/app/build.gradle
#	android/app/src/main/AndroidManifest.xml
2020-07-13 13:11:30 +06:00
Serik.Uvaissov e5f6cad039 m4bank test-app inited 2020-07-10 22:21:48 +06:00
Serik.Uvaissov f8f646279f Merge branch 'master' into nfc-android
# Conflicts:
#	lib/views/home/components/popup_menu.dart
2020-07-10 20:27:34 +06:00
Serik.Uvaissov e90982d202 android dependencies 2020-07-10 13:14:50 +06:00
Serik.Uvaissov 44e85646fd android MusicPlugin.java 2020-07-10 09:36:49 +06:00
Serik.Uvaissov 8d6ec6bfe1 android BankActivity.kt 2020-07-10 09:36:27 +06:00
111 changed files with 6999 additions and 554 deletions

View File

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

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

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
assets/images/NBK_Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
assets/images/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
assets/images/check.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/images/finger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/images/halykpos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
assets/images/phone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
assets/images/phone_fit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/images/secBg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -37,5 +37,49 @@ end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target) flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# You can enable the permissions needed here. For example to enable camera
# permission, just remove the `#` character in front so it looks like this:
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=0',
## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=0',
## dart: PermissionGroup.contacts
'PERMISSION_CONTACTS=0',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=0',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=0',
## dart: PermissionGroup.speech
'PERMISSION_SPEECH_RECOGNIZER=0',
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=0',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=0',
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=0',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=0',
## dart: PermissionGroup.sensors
'PERMISSION_SENSORS=0'
]
end
end end
end end

View File

@ -3,17 +3,25 @@ PODS:
- Flutter - Flutter
- MTBBarcodeScanner - MTBBarcodeScanner
- SwiftProtobuf - SwiftProtobuf
- charset_converter (0.0.1):
- Flutter
- device_info (0.0.1): - device_info (0.0.1):
- Flutter - Flutter
- esys_flutter_share (0.0.1): - esys_flutter_share (0.0.1):
- Flutter - Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_bluetooth_basic (0.0.1):
- Flutter
- FMDB (2.7.5): - FMDB (2.7.5):
- FMDB/standard (= 2.7.5) - FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5) - FMDB/standard (2.7.5)
- local_auth (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11) - MTBBarcodeScanner (5.0.11)
- path_provider (0.0.1): - path_provider (0.0.1):
- Flutter - Flutter
- "permission_handler (5.1.0+2)":
- Flutter
- shared_preferences (0.0.1): - shared_preferences (0.0.1):
- Flutter - Flutter
- sqflite (0.0.2): - sqflite (0.0.2):
@ -25,10 +33,14 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`) - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- charset_converter (from `.symlinks/plugins/charset_converter/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`) - device_info (from `.symlinks/plugins/device_info/ios`)
- esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_bluetooth_basic (from `.symlinks/plugins/flutter_bluetooth_basic/ios`)
- local_auth (from `.symlinks/plugins/local_auth/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
@ -42,14 +54,22 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
barcode_scan: barcode_scan:
:path: ".symlinks/plugins/barcode_scan/ios" :path: ".symlinks/plugins/barcode_scan/ios"
charset_converter:
:path: ".symlinks/plugins/charset_converter/ios"
device_info: device_info:
:path: ".symlinks/plugins/device_info/ios" :path: ".symlinks/plugins/device_info/ios"
esys_flutter_share: esys_flutter_share:
:path: ".symlinks/plugins/esys_flutter_share/ios" :path: ".symlinks/plugins/esys_flutter_share/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
flutter_bluetooth_basic:
:path: ".symlinks/plugins/flutter_bluetooth_basic/ios"
local_auth:
:path: ".symlinks/plugins/local_auth/ios"
path_provider: path_provider:
:path: ".symlinks/plugins/path_provider/ios" :path: ".symlinks/plugins/path_provider/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
sqflite: sqflite:
@ -59,17 +79,21 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479 barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
charset_converter: 215c7b04932ec2b9ba43be96a9bc34afed3e5322
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_bluetooth_basic: 0e4e27e22b50b3a25cc1d1e131953feb4af414f4
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932 SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c PODFILE CHECKSUM: 5aafc9b59da66d8d46f05cbbbd21261eb9757176
COCOAPODS: 1.8.4 COCOAPODS: 1.10.1

View File

@ -255,12 +255,13 @@
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
"${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework", "${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework",
"${BUILT_PRODUCTS_DIR}/charset_converter/charset_converter.framework",
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework", "${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
"${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework", "${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework",
"${BUILT_PRODUCTS_DIR}/local_auth/local_auth.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
@ -269,12 +270,13 @@
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/charset_converter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",

View File

@ -2,6 +2,6 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "self:">
</FileRef> </FileRef>
</Workspace> </Workspace>

View File

@ -26,8 +26,17 @@
</array> </array>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Требуется доступ к Bluetooth для подключения к принтерам и печати чеков</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Требуется доступ к Bluetooth для подключения к принтерам и печати чеков</string>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Требуется доступ к камере для сканирования QR-кодов и штрих-кодов</string> <string>Требуется доступ к камере для сканирования QR-кодов и штрих-кодов</string>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>bluetooth-peripheral</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>

View File

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

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

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

View File

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

View File

@ -34,6 +34,7 @@ class SimpleLogPrinter extends LogPrinter {
} }
String formatStackTrace(StackTrace stackTrace, int methodPosition) { String formatStackTrace(StackTrace stackTrace, int methodPosition) {
var lines = stackTrace.toString()?.split('\n'); var lines = stackTrace.toString()?.split('\n');
var formatted = <String>[]; var formatted = <String>[];
var count = 0; var count = 0;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,17 @@
class CheckImageModal {
final String base64Data;
final String textData;
CheckImageModal({this.base64Data, this.textData});
static CheckImageModal fromJson(Map<String, dynamic> json) {
return CheckImageModal(
base64Data: json['base64Data'],
textData: json['textData']
);
}
Map<String, dynamic> toJson() =>
{
'base64Data': base64Data,
'textData': textData
};
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
class SettingModel {
const SettingModel({this.name, this.type, this.address});
final String type;
final String name;
final String address;
}

View File

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

View File

@ -1,8 +1,19 @@
const String LoginViewRoute = "LoginView"; const String LoginViewRoute = "LoginView";
const String HomeViewRoute = "HomeView"; const String HomeViewRoute = "HomeView";
const String ImageShowRoute = "ImageShowRoute"; const String ImageShowRoute = "ImageShowRoute";
const String CloseDayShowRoute = "CloseDayShowRoute";
const String PaymentViewRoute = "PaymentView"; const String PaymentViewRoute = "PaymentView";
const String PaymentNfcViewRoute = "PaymentNfcViewRoute";
const String HistoryViewRoute = "HistoryView"; const String HistoryViewRoute = "HistoryView";
const String InfoKkmViewRoute = "InfoKkmViewRoute"; const String InfoKkmViewRoute = "InfoKkmViewRoute";
const String SettingsViewRoute = "SettingsViewRoute";
const String QrViewRoute = "QrViewRoute"; const String QrViewRoute = "QrViewRoute";
const String BankViewRoute = "BankViewRoute";
const String BankSettingViewRoute = "BankSettingViewRoute";
const String SettingsPrinterRoute = "SettingsPrinterRoute";
const String SettingsPrinterBTRoute = "SettingsPrinterBTRoute";
const String SettingsPrinterEncodingRoute = "SettingsPrinterEncodingRoute";
const String SettingsPrinterPaperRoute = "SettingsPrinterPaperRoute";
// Generate the views here // Generate the views here

View File

@ -1,13 +1,23 @@
import 'package:flutter/material.dart';
import 'package:aman_kassa_flutter/core/models/close_day_data.dart';
import 'package:aman_kassa_flutter/views/bank_setting/bank_setting_view.dart';
import 'package:aman_kassa_flutter/views/bank_view/bank_view.dart';
import 'package:aman_kassa_flutter/views/check/image_show_container.dart'; import 'package:aman_kassa_flutter/views/check/image_show_container.dart';
import "package:aman_kassa_flutter/views/home/home_view_m.dart";
import 'package:aman_kassa_flutter/views/close_day_view/close_day_show_container.dart';
import 'package:aman_kassa_flutter/views/history/history_view.dart'; import 'package:aman_kassa_flutter/views/history/history_view.dart';
import 'package:aman_kassa_flutter/views/info_kkm/info_kkm_view.dart'; import 'package:aman_kassa_flutter/views/info_kkm/info_kkm_view.dart';
import 'package:aman_kassa_flutter/views/payment/payment_view.dart'; import 'package:aman_kassa_flutter/views/payment/payment_view.dart';
import 'package:aman_kassa_flutter/views/payment_nfc/payment_nfc_view.dart';
import 'package:aman_kassa_flutter/views/qr_view/qr_view.dart'; import 'package:aman_kassa_flutter/views/qr_view/qr_view.dart';
import 'package:aman_kassa_flutter/views/settings/printer/views/PrinterSelect.dart';
import './route_names.dart'; import 'package:aman_kassa_flutter/views/settings/settings_view.dart';
import 'package:aman_kassa_flutter/views/home/home_view.dart'; import 'package:aman_kassa_flutter/views/settings/printer/views/PrinterEncoding.dart';
import 'package:aman_kassa_flutter/views/settings/printer/views/PrinterPaperSize.dart';
import 'package:aman_kassa_flutter/views/settings/setting_printer_view.dart';
import 'package:aman_kassa_flutter/views/login/login_view.dart'; import 'package:aman_kassa_flutter/views/login/login_view.dart';
import 'package:flutter/material.dart'; import './route_names.dart';
Route<dynamic> generateRoute(RouteSettings settings) { Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) { switch (settings.name) {
@ -15,7 +25,9 @@ Route<dynamic> generateRoute(RouteSettings settings) {
LoginModel model = settings.arguments as LoginModel; LoginModel model = settings.arguments as LoginModel;
return _getPageRoute( return _getPageRoute(
routeName: settings.name, routeName: settings.name,
viewToShow: LoginView(loginModel: model,), viewToShow: LoginView(
loginModel: model,
),
); );
case HomeViewRoute: case HomeViewRoute:
return _getPageRoute( return _getPageRoute(
@ -28,6 +40,12 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name, routeName: settings.name,
viewToShow: PaymentView(model: model), viewToShow: PaymentView(model: model),
); );
case PaymentNfcViewRoute:
PaymentModel model = settings.arguments as PaymentModel;
return _getPageRoute(
routeName: settings.name,
viewToShow: PaymentNfcView(model: model),
);
case HistoryViewRoute: case HistoryViewRoute:
return _getPageRoute( return _getPageRoute(
routeName: settings.name, routeName: settings.name,
@ -38,6 +56,21 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name, routeName: settings.name,
viewToShow: InfoKkmView(), viewToShow: InfoKkmView(),
); );
case SettingsViewRoute:
return _getPageRoute(
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: case QrViewRoute:
ImageShowModel data = settings.arguments as ImageShowModel; ImageShowModel data = settings.arguments as ImageShowModel;
return _getPageRoute( return _getPageRoute(
@ -51,6 +84,32 @@ Route<dynamic> generateRoute(RouteSettings settings) {
routeName: settings.name, routeName: settings.name,
viewToShow: ImageShowContainer(data), viewToShow: ImageShowContainer(data),
); );
case SettingsPrinterRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: SettingPrinterView(),
);
case SettingsPrinterBTRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: PrinterSelectView(),
);
case SettingsPrinterEncodingRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: PrinterEncodingView(),
);
case SettingsPrinterPaperRoute:
return _getPageRoute(
routeName: settings.name,
viewToShow: PrinterPaperView(),
);
case CloseDayShowRoute:
CloseDayData data = settings.arguments as CloseDayData;
return _getPageRoute(
routeName: settings.name,
viewToShow: CloseDayShowContainer(data),
);
default: default:
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => Scaffold( builder: (_) => Scaffold(

View File

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

View File

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

View File

@ -7,7 +7,9 @@ import 'package:aman_kassa_flutter/core/entity/Service.dart';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart'; import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/calc_model.dart'; import 'package:aman_kassa_flutter/core/models/calc_model.dart';
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/check_data.dart'; import 'package:aman_kassa_flutter/core/models/check_data.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/check_item.dart'; import 'package:aman_kassa_flutter/core/models/check_item.dart';
import 'package:aman_kassa_flutter/core/models/product_dao.dart'; import 'package:aman_kassa_flutter/core/models/product_dao.dart';
import 'package:aman_kassa_flutter/core/models/response.dart'; import 'package:aman_kassa_flutter/core/models/response.dart';
@ -135,35 +137,22 @@ class DataService extends BaseService {
return null; return null;
} }
Future<Response<dynamic>> refundM4Bank(
{
Future<Response<dynamic>> sellOrReturn( String token,
{String paymentType, CheckData checkData,
String tradeType, CardData cardData}) async {
String token,
List<ProductDao> kassaItems,
List<CalcModel> calcItems,
String operationType,
String mode}) async {
try { try {
String data; var json = cardData.toJson();
if (mode == SettingModeKassa) { json['transactionType'] = VoucherTypeReturnPay;
CheckData checkData = _transformProductsToCheckData( checkData.cardData = CardData.fromJson(json);
paymentType: paymentType, tradeType: tradeType, items: kassaItems); String data = jsonEncode(checkData.toJson());
data = jsonEncode(checkData.toJson());
} else if (mode == SettingModeCalc) {
CheckData checkData = _transformCalcModelToCheckData(
paymentType: paymentType, tradeType: tradeType, items: calcItems);
data = jsonEncode(checkData.toJson());
}
// log.i('token: $token'); log.i('token: $token');
// log.i('data: $data'); log.i('data: $data');
Response<dynamic> response = await (operationType == OperationTypePay Response<dynamic> response = await _api.sellReturn(token, data);
? _api.sell(token, data) log.i('response status: ${response.status}');
: _api.sellReturn(token, data)); log.i('response operation: ${response.operation}');
// log.i('response status: ${response.status}');
// log.i('response operation: ${response.operation}');
if (response.status == 200 && response.operation == true) { if (response.status == 200 && response.operation == true) {
User user = Redux.store.state.userState.user; User user = Redux.store.state.userState.user;
String check = response?.body['check']; String check = response?.body['check'];
@ -179,6 +168,69 @@ class DataService extends BaseService {
base64Data: check, base64Data: check,
total: total, total: total,
url: url, url: url,
type: VoucherTypeReturnPay);
}
return response;
} catch (e, stack) {
log.e("sellOrReturn", e, stack);
}
return null;
}
Future<Response<dynamic>> sellOrReturn(
{String paymentType,
String tradeType,
String token,
List<ProductDao> kassaItems,
List<CalcModel> calcItems,
String operationType,
String mode,
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());
}
// log.i('token: $token');
// log.i('data: $data');
Response<dynamic> response = await (operationType == OperationTypePay
? _api.sell(token, data)
: _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;
//check compare
String check = response?.body['check'];
var checkText = response?.body['check_text'];
CheckImageModal imageModal = new CheckImageModal( base64Data: check, textData: checkText !=null ? jsonEncode(checkText) : null );
// journal analyze
dynamic journal = response?.body['journal'];
int checkNum = journal['check_num'];
var summ = journal['summ'];
// short url
String url = response?.body['link'];
// total
double total = summ != null ? double.parse(summ.toString()) : 0.0;
//insert data to db
this.insertVoucher(
user: user,
name: 'Чек №$checkNum',
data: data,
base64Data: jsonEncode(imageModal.toJson()),
total: total,
url: url,
type: operationType == OperationTypeReturn type: operationType == OperationTypeReturn
? VoucherTypeReturnPay ? VoucherTypeReturnPay
: VoucherTypePayment); : VoucherTypePayment);

View File

@ -1,12 +1,13 @@
//general //general
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'dart:io';
import 'package:aman_kassa_flutter/shared/app_colors.dart'; import 'package:aman_kassa_flutter/shared/app_colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_screenutil/screenutil_init.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
//service & tools //service & tools
import 'package:aman_kassa_flutter/redux/store.dart'; import 'package:aman_kassa_flutter/redux/store.dart';
@ -21,6 +22,8 @@ import 'views/start_up/start_up_view.dart';
//main start //main start
void main() async { void main() async {
HttpOverrides.global = MyHttpOverrides();
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides(); HttpOverrides.global = MyHttpOverrides();
//initialize locator //initialize locator
@ -35,41 +38,45 @@ void main() async {
runApp(MainApplication()); runApp(MainApplication());
} }
class MainApplication extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: Redux.store,
child: ScreenUtilInit(
designSize: Size(411.43, 683.43),
allowFontScaling: false,
builder: () => MaterialApp(
theme: ThemeData(
backgroundColor: backgroundColor,
primaryColor: primaryColor,
accentColor: yellowColor,
scaffoldBackgroundColor: Colors.white,
textTheme: GoogleFonts.latoTextTheme(
Theme.of(context).textTheme,
)
),
debugShowCheckedModeBanner: false,
builder: (context, child) => Navigator(
key: locator<DialogService>().dialogNavigationKey,
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => DialogManager(child: child)),
),
navigatorKey: locator<NavigatorService>().navigatorKey,
home: StartUpView(), // first page
onGenerateRoute: generateRoute,
),
),
);
}
}
class MyHttpOverrides extends HttpOverrides{ class MyHttpOverrides extends HttpOverrides{
@override @override
HttpClient createHttpClient(SecurityContext context){ HttpClient createHttpClient(SecurityContext context){
return super.createHttpClient(context) return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true; ..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
} }
}
class MainApplication extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: Redux.store,
child: MaterialApp(
theme: ThemeData(
backgroundColor: backgroundColor,
primaryColor: primaryColor,
accentColor: yellowColor,
scaffoldBackgroundColor: Colors.white,
textTheme: GoogleFonts.latoTextTheme(
Theme.of(context).textTheme,
)
),
debugShowCheckedModeBanner: false,
builder: (context, child) => Navigator(
key: locator<DialogService>().dialogNavigationKey,
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => DialogManager(child: child)),
),
navigatorKey: locator<NavigatorService>().navigatorKey,
home: StartUpView(), // first page
onGenerateRoute: generateRoute,
),
);
}
} }

View File

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

View File

@ -3,7 +3,7 @@ import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:redux/redux.dart'; import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart'; import 'package:redux_thunk/redux_thunk.dart';
import 'package:flutter_bluetooth_basic/src/bluetooth_device.dart';
import '../store.dart'; import '../store.dart';
@immutable @immutable
@ -23,4 +23,40 @@ ThunkAction<AppState> changeTradeTypeFromSetting(String tradeType) {
return (Store<AppState> store) async { return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(tradeType: tradeType ))); store.dispatch(SetSettingStateAction(SettingState(tradeType: tradeType )));
}; };
}
ThunkAction<AppState> changePinCodeFromSetting(String pinCode) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(pinCode: pinCode)));
};
}
ThunkAction<AppState> changePinLockedFromSetting(bool locked) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(pinLocked: locked)));
};
}
ThunkAction<AppState> changePinSkipFromSetting(bool skip) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(pinSkip: skip)));
};
}
ThunkAction<AppState> selectPrinterFromSetting(BluetoothDevice device) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(printerBT: device )));
};
}
ThunkAction<AppState> selectPrinterEncodingFromSetting(String encoding) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(printerEncoding: encoding )));
};
}
ThunkAction<AppState> selectPrinterPaperSizeFromSetting(String paperSize) {
return (Store<AppState> store) async {
store.dispatch(SetSettingStateAction(SettingState(printerPaperSize: paperSize )));
};
} }

View File

@ -72,7 +72,7 @@ Future<void> logoutAction(Store<AppState> store) async {
UserState( UserState(
isLoading: false, isLoading: false,
isAuthenticated: false, isAuthenticated: false,
user: User(), user: User()
), ),
), ),
); );

View File

@ -3,4 +3,17 @@ const String SettingModeCalc = 'calcMode';
const String SettingTradeTypeGood = 'g'; const String SettingTradeTypeGood = 'g';
const String SettingTradeTypeService = 's'; const String SettingTradeTypeService = 's';
const String SettingPrinterEncodingCp866 = 'cp866';
const String SettingPrinterEncodingWin1251 = 'windows-1251';
const String SettingPrinterEncodingImage = 'image';
const String SettingPrinterPaperM58 = '58mm';
const String SettingPrinterPaperM80 = '80mm';

View File

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

View File

@ -5,6 +5,12 @@ settingReducer(SettingState prevState, SetSettingStateAction action) {
final payload = action.settingState; final payload = action.settingState;
return prevState.copyWith( return prevState.copyWith(
mode: payload.mode, mode: payload.mode,
tradeType: payload.tradeType tradeType: payload.tradeType,
pinCode: payload.pinCode,
pinLocked: payload.pinLocked,
pinSkip: payload.pinSkip,
printerBT: payload.printerBT,
printerEncoding: payload.printerEncoding,
printerPaperSize: payload.printerPaperSize,
); );
} }

View File

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

View File

@ -1,28 +1,58 @@
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart'; import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:flutter_bluetooth_basic/src/bluetooth_device.dart';
@immutable @immutable
class SettingState { class SettingState {
final String mode; final String mode;
final String tradeType; final String tradeType;
final String pinCode;
final bool pinLocked;
final bool pinSkip;
final BluetoothDevice printerBT;
final String printerEncoding;
final String printerPaperSize;
SettingState({this.mode, this.tradeType});
SettingState({this.mode, this.tradeType, this.pinCode, this.pinLocked, this.pinSkip, this.printerBT,
this.printerEncoding,
this.printerPaperSize});
//read hive //read hive
factory SettingState.initial(SettingState payload) { factory SettingState.initial(SettingState payload) {
return SettingState( return SettingState(
mode: payload?.mode ?? SettingModeKassa, mode: payload?.mode ?? SettingModeKassa,
tradeType: payload?.tradeType ?? SettingTradeTypeGood); tradeType: payload?.tradeType ?? SettingTradeTypeGood,
pinCode: payload?.pinCode ?? null,
pinLocked: true,
pinSkip: false,
printerBT: payload?.printerBT ?? null,
printerEncoding:
payload?.printerEncoding ?? SettingPrinterEncodingCp866,
printerPaperSize: payload?.printerPaperSize ?? SettingPrinterPaperM58
);
} }
//write hive //write hive
SettingState copyWith({ SettingState copyWith({
@required mode, @required mode,
@required tradeType, @required tradeType,
@required pinCode,
@required pinLocked,
@required pinSkip,
@required printerBT,
@required printerEncoding,
@required printerPaperSize,
}) { }) {
return SettingState( return SettingState(
mode: mode ?? this.mode, mode: mode ?? this.mode,
tradeType: tradeType ?? this.tradeType, tradeType: tradeType ?? this.tradeType,
pinCode: pinCode ?? this.pinCode,
pinLocked: pinLocked ?? this.pinLocked,
pinSkip: pinSkip ?? this.pinSkip,
printerBT: printerBT ?? this.printerBT,
printerEncoding: printerEncoding ?? this.printerEncoding,
printerPaperSize: printerPaperSize ?? this.printerPaperSize
); );
} }
@ -31,11 +61,28 @@ class SettingState {
? SettingState( ? SettingState(
tradeType: json['tradeType'], tradeType: json['tradeType'],
mode: json['mode'], mode: json['mode'],
pinCode: json['pinCode'],
pinLocked: json['pinLocked'],
pinSkip: json['pinSkip'],
printerEncoding: json['printerEncoding'],
printerPaperSize: json['printerPaperSize'],
printerBT: json['printerBT'] != null
? BluetoothDevice.fromJson(json['printerBT'])
: null,
) )
: null; : null;
} }
dynamic toJson() { dynamic toJson() {
return {"tradeType": tradeType, "mode": mode}; return {
"tradeType": tradeType,
"mode": mode,
"pinCode": pinCode,
"pinLocked" : pinLocked,
"pinSkip" : pinSkip,
"printerBT": printerBT != null ? printerBT.toJson() : null,
"printerEncoding": printerEncoding,
"printerPaperSize": printerPaperSize,
};
} }
} }

View File

@ -16,6 +16,7 @@ class UserState {
final Smena smena; final Smena smena;
final Money money; final Money money;
UserState( UserState(
{this.isError, {this.isError,
this.isLoading, this.isLoading,
@ -26,7 +27,8 @@ class UserState {
this.user, this.user,
this.loginFormMessage, this.loginFormMessage,
this.smena, this.smena,
this.money}); this.money,
});
factory UserState.initial(UserState payload) => UserState( factory UserState.initial(UserState payload) => UserState(
isLoading: false, isLoading: false,
@ -73,7 +75,8 @@ class UserState {
user: User.fromJson(json['user']), user: User.fromJson(json['user']),
authenticateType: json['authenticateType'], authenticateType: json['authenticateType'],
login: json['login'], login: json['login'],
password: json['password']) password: json['password'],
)
: null; : null;
} }

View File

@ -1,10 +1,12 @@
import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/reducers/bank_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/calc_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/calc_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/main_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/main_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/setting_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/setting_reducer.dart';
import 'package:aman_kassa_flutter/redux/reducers/user_reducer.dart'; import 'package:aman_kassa_flutter/redux/reducers/user_reducer.dart';
import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
import 'package:aman_kassa_flutter/redux/state/calc_state.dart'; import 'package:aman_kassa_flutter/redux/state/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart'; import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
import 'package:aman_kassa_flutter/redux/state/setting_state.dart'; import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
@ -15,6 +17,7 @@ import 'package:redux_persist_flutter/redux_persist_flutter.dart';
import 'package:redux_thunk/redux_thunk.dart'; import 'package:redux_thunk/redux_thunk.dart';
import 'package:redux_persist/redux_persist.dart'; import 'package:redux_persist/redux_persist.dart';
import 'actions/bank_actions.dart';
import 'actions/calc_actions.dart'; import 'actions/calc_actions.dart';
//reducer context //reducer context
@ -35,6 +38,10 @@ AppState appReducer(AppState state, dynamic action) {
/** CalcAction **/ /** CalcAction **/
final nextCalcState = calcReducer(state.calcState, action); final nextCalcState = calcReducer(state.calcState, action);
return state.copyWith(calcState: nextCalcState); return state.copyWith(calcState: nextCalcState);
} else if (action is SetBankStateAction) {
/** BankAction **/
final nextBankState = bankReducer(state.bankState, action);
return state.copyWith(bankState: nextBankState);
} }
return state; return state;
} }
@ -46,12 +53,14 @@ class AppState {
final KassaState kassaState; final KassaState kassaState;
final SettingState settingState; final SettingState settingState;
final CalcState calcState; final CalcState calcState;
final BankState bankState;
AppState({ AppState({
this.userState, this.userState,
this.kassaState, this.kassaState,
this.settingState, this.settingState,
this.calcState, this.calcState,
this.bankState,
}); });
//stable work //stable work
@ -60,28 +69,32 @@ class AppState {
KassaState kassaState, KassaState kassaState,
SettingState settingState, SettingState settingState,
CalcState calcState, CalcState calcState,
BankState bankState,
}) { }) {
return AppState( return AppState(
userState: userState ?? this.userState, userState: userState ?? this.userState,
kassaState: kassaState ?? this.kassaState, kassaState: kassaState ?? this.kassaState,
settingState: settingState ?? this.settingState, settingState: settingState ?? this.settingState,
calcState: calcState ?? this.calcState, calcState: calcState ?? this.calcState,
bankState: bankState ?? this.bankState,
); );
} }
static AppState fromJson(dynamic json){ static AppState fromJson(dynamic json) {
return json !=null return json != null
? AppState( ? AppState(
settingState: SettingState.fromJson(json['settingState']), settingState: SettingState.fromJson(json['settingState']),
userState: UserState.fromJson(json['userState']), userState: UserState.fromJson(json['userState']),
) bankState: BankState.fromJson(json['bankState']),
)
: null; : null;
} }
dynamic toJson() { dynamic toJson() {
return { return {
"settingState": settingState.toJson(), "settingState": settingState.toJson(),
"userState" : userState.toJson(), "userState": userState.toJson(),
"bankState": bankState.toJson(),
}; };
} }
} }
@ -102,7 +115,8 @@ class Redux {
// Create Persistor // Create Persistor
final persist = Persistor<AppState>( final persist = Persistor<AppState>(
storage: FlutterStorage(), // Or use other engines storage: FlutterStorage(), // Or use other engines
serializer: JsonSerializer<AppState>(AppState.fromJson), // Or use other serializers serializer: JsonSerializer<AppState>(
AppState.fromJson), // Or use other serializers
); );
final initialState = await persist.load(); final initialState = await persist.load();
@ -111,15 +125,17 @@ class Redux {
final kassaStateInitial = KassaState.initial(); final kassaStateInitial = KassaState.initial();
final settingStateInitial = SettingState.initial(initialState?.settingState); final settingStateInitial = SettingState.initial(initialState?.settingState);
final calcStateInitial = CalcState.initial(); final calcStateInitial = CalcState.initial();
final bankStateInitial = BankState.initial(initialState?.bankState);
_store = Store<AppState>( _store = Store<AppState>(
appReducer, appReducer,
middleware: [thunkMiddleware, persist.createMiddleware() ], middleware: [thunkMiddleware, persist.createMiddleware()],
initialState: AppState( initialState: AppState(
userState: userStateInitial, userState: userStateInitial,
kassaState: kassaStateInitial, kassaState: kassaStateInitial,
settingState: settingStateInitial, settingState: settingStateInitial,
calcState: calcStateInitial), calcState: calcStateInitial,
bankState: bankStateInitial),
); );
} }
} }

View File

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

View File

@ -24,6 +24,8 @@ const TextStyle productTextStyle = const TextStyle(
fontWeight: FontWeight.w400, color: Colors.black, fontSize: 15); fontWeight: FontWeight.w400, color: Colors.black, fontSize: 15);
const TextStyle buttonTitleTextStyle = const TextStyle( const TextStyle buttonTitleTextStyle = const TextStyle(
fontWeight: FontWeight.w700, color: whiteColor, fontSize: 14); fontWeight: FontWeight.w700, color: whiteColor, fontSize: 14);
const TextStyle buttonTitleDisableTextStyle = const TextStyle(
fontWeight: FontWeight.w700, color: fillColor, fontSize: 14);
const TextStyle buttonBigTitleTextStyle = const TextStyle( const TextStyle buttonBigTitleTextStyle = const TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: whiteColor, color: whiteColor,

View File

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

View File

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

View File

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

View File

@ -1,34 +1,153 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:aman_kassa_flutter/core/entity/Voucher.dart';
import 'package:aman_kassa_flutter/core/locator.dart'; import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/models/check_data.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/aman_dao.dart';
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/dialog_models.dart'; import 'package:aman_kassa_flutter/core/models/dialog_models.dart';
import 'package:aman_kassa_flutter/core/models/response.dart';
import 'package:aman_kassa_flutter/core/route_names.dart'; import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart'; import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:aman_kassa_flutter/redux/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/app_colors.dart';
import 'package:aman_kassa_flutter/shared/ui_helpers.dart'; import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
import 'package:aman_kassa_flutter/views/settings/printer/PrinterTest.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import 'package:aman_kassa_flutter/widgets/fields/busy_button_icon.dart'; import 'package:aman_kassa_flutter/widgets/fields/busy_button_icon.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class ImageShowContainer extends StatelessWidget { import '../../core/models/aman_dao.dart';
final ImageShowModel data;
ImageShowContainer(this.data); class ImageShowContainer extends StatefulWidget {
final ImageShowModel showModel;
ImageShowContainer(this.showModel);
@override
_ImageShowContainerState createState() => _ImageShowContainerState();
}
class _ImageShowContainerState extends State<ImageShowContainer> {
final PrinterBluetoothManager printerManager = PrinterBluetoothManager();
final DialogService _dialogService = locator<DialogService>();
final BluetoothDevice printerBtDevice = Redux.store.state.settingState.printerBT;
final BluetoothManager bluetoothManager = BluetoothManager.instance;
bool _printing = false;
void _preparePrint() async {
if (Platform.isIOS) {
await _print();
} else {
bluetoothManager.state.listen((val) {
print("state = $val");
if (!mounted) return;
if (val == 12) {
print('on');
_print();
} else if (val == 10) {
print('off');
_dialogService.showDialog(description: 'Отсутвует соеденение Bluetooth или он отключен', title: 'Bluetooth');
}
print('state is $val');
});
}
}
void _print() async {
final SettingState state = Redux.store.state.settingState;
if (state.printerBT == null) {
_dialogService.showDialog(description: 'Укажите в настройках принтер для печати чеков');
return;
}
bool isIos = Platform.isIOS;
int chunkSizeBytes = 3096;
int queueSleepTimeMs = 100;
if (isIos) {
chunkSizeBytes = 75;
queueSleepTimeMs = 10;
}
setState(() {
_printing = true;
});
try {
printerManager.selectPrinter(PrinterBluetooth(state.printerBT));
PaperSize paper = state.printerPaperSize == SettingPrinterPaperM80 ? PaperSize.mm80 : PaperSize.mm58;
if (SettingPrinterEncodingImage == state.printerEncoding) {
final PosPrintResult res = await printerManager.printTicket(
await printImageCheck(paper, widget.showModel.data.base64Data),
chunkSizeBytes: chunkSizeBytes,
queueSleepTimeMs: queueSleepTimeMs);
if (res.value != 1) {
_dialogService.showDialog(description: res.msg);
}
} else {
final PosPrintResult res = await printerManager.printTicket(
await printTextCheck(paper, state.printerEncoding, jsonDecode(widget.showModel.data.textData)),
chunkSizeBytes: chunkSizeBytes,
queueSleepTimeMs: queueSleepTimeMs);
if (res.value != 1) {
_dialogService.showDialog(description: res.msg);
}
}
} catch (e) {
print(e);
}
await Future.delayed(Duration(seconds: 7));
setState(() {
_printing = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
//backgroundColor: fillColor, //backgroundColor: fillColor,
title: Text(data.title), title: Text(widget.showModel.title),
actions: [
if (_printing)
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SizedBox(
width: 36.0,
child: Center(
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: new AlwaysStoppedAnimation<Color>(whiteColor),
),
),
),
)
else
IconButton(icon: Icon(Icons.print), onPressed: _preparePrint)
],
), ),
body: ListView( body: ListView(
children: <Widget>[imageFromBase64String(data.data)], children: <Widget>[imageFromBase64String(widget.showModel.data.base64Data)],
), ),
floatingActionButton: MyFloatingActionButton(data), floatingActionButton: MyFloatingActionButton(widget.showModel),
); );
} }
} }
@ -41,16 +160,20 @@ Padding imageFromBase64String(String base64String) {
} }
class ImageShowModel { class ImageShowModel {
final String data; final CheckImageModal data;
final String title; final String title;
final String url; final String url;
final CardData cardData;
final Voucher voucher;
ImageShowModel({this.data, this.title, this.url}); ImageShowModel({this.data, this.title, this.url, this.cardData, this.voucher});
} }
class MyFloatingActionButton extends StatefulWidget { class MyFloatingActionButton extends StatefulWidget {
final ImageShowModel data; final ImageShowModel data;
MyFloatingActionButton(this.data); MyFloatingActionButton(this.data);
@override @override
_MyFloatingActionButtonState createState() => _MyFloatingActionButtonState(); _MyFloatingActionButtonState createState() => _MyFloatingActionButtonState();
} }
@ -59,11 +182,101 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
bool showFab = true; bool showFab = true;
DialogService _dialog = locator<DialogService>(); DialogService _dialog = locator<DialogService>();
NavigatorService _navigatorService = locator<NavigatorService>(); NavigatorService _navigatorService = locator<NavigatorService>();
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final DataService _dataService = locator<DataService>();
double sheetHeight = 260;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return showFab //print(widget.data.cardData.transactionType);
? FloatingActionButton( if (showFab) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (widget.data.cardData != null && 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 == null
|| Redux.store.state.userState.smena == null
|| Redux.store.state.userState.smena.startedAt == null
|| yesterday.isAfter(Redux.store.state.userState.smena.startedAt)) {
_dialog.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
try {
await Redux.store.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> response = await reversalHalykPos(widget.data.cardData, widget.data.voucher.total);
if (response.success) {
pressRefund();
} else {
_dialog.showDialog(description: response.msg);
}
} finally {
await Redux.store.dispatch(changePinSkipFromSetting(false));
}
_navigatorService.replace(HomeViewRoute);
},
heroTag: null,
)
else
SizedBox(
height: 0,
),
SizedBox(
height: 10,
),
if (widget.data.cardData != null && widget.data.cardData.transactionType == "payment")
FloatingActionButton(
backgroundColor: redColor,
tooltip: 'Возврат',
child: Icon(
Icons.settings_backup_restore,
color: whiteColor,
),
onPressed: () async {
var today = new DateTime.now();
var yesterday = today.subtract(new Duration(days: 1));
if( Redux.store.state.userState == null
|| Redux.store.state.userState.smena == null
|| Redux.store.state.userState.smena.startedAt == null
|| yesterday.isAfter(Redux.store.state.userState.smena.startedAt)) {
_dialog.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
try {
await Redux.store.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> response = await refundHalykPos(widget.data.cardData, widget.data.voucher.total);
if (response.success) {
pressRefund();
} else {
_dialog.showDialog(description: response.msg);
}
} finally {
await Redux.store.dispatch(changePinSkipFromSetting(false));
}
},
heroTag: null,
)
else
SizedBox(
height: 0,
),
SizedBox(
height: 10,
),
FloatingActionButton(
child: Icon(Icons.share), child: Icon(Icons.share),
onPressed: () { onPressed: () {
var bottomSheetController = showBottomSheet( var bottomSheetController = showBottomSheet(
@ -73,12 +286,7 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(15)), borderRadius: BorderRadius.all(Radius.circular(15)),
boxShadow: [ boxShadow: [BoxShadow(blurRadius: 10, color: Colors.grey[300], spreadRadius: 5)]),
BoxShadow(
blurRadius: 10,
color: Colors.grey[300],
spreadRadius: 5)
]),
height: 260, height: 260,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
@ -107,36 +315,75 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
), ),
], ],
))); )));
showFoatingActionButton(false); showFloatingActionButton(false);
bottomSheetController.closed.then((value) { bottomSheetController.closed.then((value) {
showFoatingActionButton(true); showFloatingActionButton(true);
}); });
}, },
) ),
: Container(); ],
);
} else {
return Container();
}
}
pressRefund() async {
Dialogs.showLoadingDialog(context, _keyLoader);
try {
AppState _state = Redux.store.state;
String _token = _state.userState.user.token;
CardData _cardData = widget.data.cardData;
CheckData _checkData = CheckData.fromJson(json.decode(widget.data.voucher.data));
Response<dynamic> response =
await _dataService.refundM4Bank(token: _token, cardData: _cardData, checkData: _checkData);
if (response != null) {
if (response.operation) {
String message = response.body['message'];
String check = response.body['check'];
var checkText = response.body['check_text'];
String url = response?.body['link'];
print('url : $url');
Redux.store.dispatch(checkMoney);
Redux.store.dispatch(openSmenaPseudo);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_navigatorService.replace(HomeViewRoute);
_navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(
data: new CheckImageModal(
base64Data: check, textData: checkText != null ? jsonEncode(checkText) : null),
title: message,
url: url));
} else if (!response.operation && ![401, 402, 403, 412, 500].contains(response.status)) {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_dialog.showDialog(description: response.body['message']);
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} catch (e) {
print(e);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
}
} }
void shareFile() async { void shareFile() async {
try { try {
await Share.file('Aman Kassa', 'aman_kassa_check.png', await Share.file('Aman Kassa', 'aman_kassa_check.png', base64Decode(widget.data.data.base64Data), 'image/png');
base64Decode(widget.data.data), 'image/png');
} catch (e) { } catch (e) {
print('error: $e'); print('error: $e');
} }
} }
void qrGenerate() async { void qrGenerate() async {
_navigatorService.push(QrViewRoute, _navigatorService.push(QrViewRoute, arguments: ImageShowModel(url: widget.data.url, title: 'Спасибо за покупку'));
arguments:
ImageShowModel(data: widget.data.url, title: 'Спасибо за покупку'));
} }
void callWhatsApp() async { void callWhatsApp() async {
DialogResponse response = await _dialog.showConfirmationDialogInput( DialogResponse response = await _dialog.showConfirmationDialogInput(
description: 'Номер телефона', description: 'Номер телефона', cancelTitle: 'Отмена', confirmationTitle: 'Отправить', formatType: 'phone');
cancelTitle: 'Отмена',
confirmationTitle: 'Отправить',
formatType: 'phone');
if (response.confirmed) { if (response.confirmed) {
String phoneNumber = response.responseText; String phoneNumber = response.responseText;
String msg = "Спасибо за покупку! \r\n ${widget.data.url} "; String msg = "Спасибо за покупку! \r\n ${widget.data.url} ";
@ -156,7 +403,6 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
} }
} }
print(url());
if (await canLaunch(url())) { if (await canLaunch(url())) {
await launch(url()); await launch(url());
} else { } else {
@ -164,7 +410,7 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
} }
} }
void showFoatingActionButton(bool value) { void showFloatingActionButton(bool value) {
setState(() { setState(() {
showFab = value; showFab = value;
}); });

View File

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

View File

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

View File

@ -24,29 +24,36 @@ class BottomBar extends StatelessWidget {
currentIndex: selectedTabIndex, currentIndex: selectedTabIndex,
backgroundColor: menuColor, backgroundColor: menuColor,
type: BottomNavigationBarType.shifting, type: BottomNavigationBarType.shifting,
showUnselectedLabels: true,
items: [ items: [
vm.mode == SettingModeKassa vm.mode == SettingModeKassa
? BottomNavigationBarItem( ? BottomNavigationBarItem(
backgroundColor: menuColor, backgroundColor: menuColor,
icon: Icon(MdiIcons.cashRegister, color: Colors.white), icon: Icon(MdiIcons.cashRegister, color: Colors.white),
title: new Text( label: 'Касса',
'Касса', // title: new Text(
style: TextStyle(color: Colors.white), // 'Касса',
)) // style: TextStyle(color: Colors.white),
// )
)
: BottomNavigationBarItem( : BottomNavigationBarItem(
backgroundColor: menuColor, backgroundColor: menuColor,
icon: Icon(MdiIcons.calculator, color: Colors.white), icon: Icon(MdiIcons.calculator, color: Colors.white),
title: new Text( label: 'Калькулятор',
'Калькулятор', // title: new Text(
style: TextStyle(color: Colors.white), // 'Калькулятор',
)), // style: TextStyle(color: Colors.white),
// )
),
BottomNavigationBarItem( BottomNavigationBarItem(
backgroundColor: menuColor, backgroundColor: menuColor,
icon: Icon(MdiIcons.tune, color: Colors.white), icon: Icon(MdiIcons.tune, color: Colors.white),
title: new Text( label: 'Опции'
'Опции', // title: new Text(
style: TextStyle(color: Colors.white), // 'Опции',
)), // style: TextStyle(color: Colors.white),
// )
),
], ],
onTap: (index) { onTap: (index) {
pageController.animateToPage( pageController.animateToPage(

View File

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

View File

@ -1,107 +0,0 @@
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/logger.dart';
import 'package:aman_kassa_flutter/core/models/choice.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/ApiService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.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/views/home/components/header_title.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:logger/logger.dart';
import './tabs/KassaTab.dart';
import './tabs/AdditionalTab.dart';
import './tabs/CalculatorTab.dart';
import './components/popup_menu.dart';
import 'components/bottom_bar.dart';
class HomeView extends StatefulWidget {
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
Logger log = getLogger('HomeView');
PageController pageController;
int selectedTabIndex;
DataService _dataService = locator<DataService>();
ApiService _api = locator<ApiService>();
NavigatorService _navigatorService = locator<NavigatorService>();
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
@override
void initState() {
super.initState();
selectedTabIndex = 0;
pageController = new PageController(initialPage: selectedTabIndex);
Redux.store.dispatch(checkSmena);
_dataService.checkDbFill(Redux.store.state.userState.user);
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
void _onSelectChoice(Choice choice) async {
if (choice.command == 'exit') {
Dialogs.showLoadingDialog(context, _keyLoader);
Response<dynamic> result = await _api.logout(Redux.store.state.userState.user.token);
if(result.operation && result.status == 200) {
Redux.store.dispatch(logoutAction);
}
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} else if (choice.command == 'infokkm') {
_navigatorService.push(InfoKkmViewRoute);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 5.0,
brightness: Brightness.light,
title: HeaderTitle(),
actions: <Widget>[
PopupMenu(
onSelectChoice: _onSelectChoice,
)
],
backgroundColor: fillColor,
),
body:StoreConnector<AppState, SettingState>(
converter: (store) => store.state.settingState,
builder: (context, vm) {
return PageView(
onPageChanged: (index) {
setState(() {
selectedTabIndex = index;
});
},
controller: pageController,
children: <Widget>[
vm.mode == SettingModeKassa ? KassaTab(0) : CalculatorTab(0),
AdditionalTab(1),
],
);
}
),
bottomNavigationBar: BottomBar(
pageController: pageController,
selectedTabIndex: selectedTabIndex,
),
);
}
}

View File

@ -0,0 +1,201 @@
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/logger.dart';
import 'package:aman_kassa_flutter/core/models/choice.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/ApiService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.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/views/home/components/header_title.dart';
import 'package:aman_kassa_flutter/views/lockscreen/passcodescreen.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:logger/logger.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './tabs/KassaTab.dart';
import './tabs/AdditionalTab.dart';
import './tabs/CalculatorTab.dart';
import './components/popup_menu.dart';
import './components/bottom_bar.dart';
class HomeView extends StatefulWidget {
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> with WidgetsBindingObserver {
Logger log = getLogger('HomeView');
PageController pageController;
int selectedTabIndex;
DataService _dataService = locator<DataService>();
ApiService _api = locator<ApiService>();
NavigatorService _navigatorService = locator<NavigatorService>();
final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final lastKnownStateKey = 'lastKnownStateKey';
final backgroundedTimeKey = 'backgroundedTimeKey';
final pinLockMillis = 2000; // 2 seconds
Future _paused() async {
final sp = await SharedPreferences.getInstance();
sp.setInt(lastKnownStateKey, AppLifecycleState.paused.index);
}
Future _inactive() async {
final sp = await SharedPreferences.getInstance();
final prevState = sp.getInt(lastKnownStateKey);
final prevStateIsNotPaused = prevState != null &&
AppLifecycleState.values[prevState] != AppLifecycleState.paused;
final bool pinIsExist = Redux.store.state.settingState?.pinCode?.isNotEmpty;
final bool pinSkipped = Redux.store.state.settingState.pinSkip;
print('prevStateIsNotPaused=$prevStateIsNotPaused, pinIsExist=$pinIsExist, pinSkipped=$pinSkipped');
if(prevStateIsNotPaused && pinSkipped == false && pinIsExist == true) {
// save App backgrounded time to Shared preferences
sp.setInt(backgroundedTimeKey, DateTime.now().millisecondsSinceEpoch);
}
// update previous state as inactive
sp.setInt(lastKnownStateKey, AppLifecycleState.inactive.index);
}
Future _resumed() async {
final sp = await SharedPreferences.getInstance();
final bgTime = sp.getInt(backgroundedTimeKey) ?? 0;
final allowedBackgroundTime = bgTime + pinLockMillis;
final shouldShowPIN = DateTime.now().millisecondsSinceEpoch > allowedBackgroundTime;
if(shouldShowPIN && bgTime > 0) {
await Redux.store.dispatch(changePinLockedFromSetting(true));
pushToLockScreen();
}
sp.remove(backgroundedTimeKey); // clean
sp.setInt(lastKnownStateKey, AppLifecycleState.resumed.index);// previous state
}
void pushToLockScreen() {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) =>
WillPopScope(
onWillPop: () async {
return false;
},
child: PassCodeScreen( title: 'Безопасность',)
)
));
}
_checkLockPin () async {
final bool pinIsExist = Redux.store.state.settingState?.pinCode?.isNotEmpty;
final bool pinLocked = Redux.store.state.settingState?.pinLocked;
final sp = await SharedPreferences.getInstance();
sp.remove(backgroundedTimeKey);
sp.setInt(lastKnownStateKey, AppLifecycleState.resumed.index);// previous state
if ( pinIsExist == true && pinLocked == true ) {
await Future.delayed(Duration(milliseconds: 50));
pushToLockScreen();
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
selectedTabIndex = 0;
pageController = new PageController(initialPage: selectedTabIndex);
Redux.store.dispatch(checkSmena);
_dataService.checkDbFill(Redux.store.state.userState.user);
_checkLockPin();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print('state = $state');
switch(state) {
case AppLifecycleState.resumed:
_resumed();
break;
case AppLifecycleState.paused:
_paused();
break;
case AppLifecycleState.inactive:
_inactive();
break;
default:
break;
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
pageController.dispose();
super.dispose();
}
void _onSelectChoice(Choice choice) async {
if (choice.command == 'exit') {
Dialogs.showLoadingDialog(context, _keyLoader);
Response<dynamic> result =
await _api.logout(Redux.store.state.userState.user.token);
if (result.operation && result.status == 200) {
Redux.store.dispatch(logoutAction);
}
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} else if (choice.command == 'infokkm') {
_navigatorService.push(InfoKkmViewRoute);
} else if (choice.command == 'settings') {
_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);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 5.0,
brightness: Brightness.light,
title: HeaderTitle(),
actions: <Widget>[
PopupMenu(
onSelectChoice: _onSelectChoice,
)
],
backgroundColor: fillColor,
),
body: StoreConnector<AppState, SettingState>(
converter: (store) => store.state.settingState,
builder: (context, vm) {
return PageView(
onPageChanged: (index) {
setState(() {
selectedTabIndex = index;
});
},
controller: pageController,
children: <Widget>[
vm.mode == SettingModeKassa ? KassaTab(0) : CalculatorTab(0),
AdditionalTab(1),
],
);
}),
bottomNavigationBar: BottomBar(
pageController: pageController,
selectedTabIndex: selectedTabIndex,
),
);
}
}

View File

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

View File

@ -6,6 +6,7 @@ import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart'; import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/operation_const.dart'; import 'package:aman_kassa_flutter/redux/constants/operation_const.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart'; import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart'; import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
@ -183,6 +184,7 @@ class KassaTab extends StatelessWidget {
Future<void> scan() async { Future<void> scan() async {
try { try {
await Redux.store.dispatch(changePinSkipFromSetting(true));
var options = ScanOptions(strings: { var options = ScanOptions(strings: {
"cancel": 'Отмена', "cancel": 'Отмена',
"flash_on": 'Вкл фонарик', "flash_on": 'Вкл фонарик',
@ -217,7 +219,7 @@ class KassaTab extends StatelessWidget {
List<Good> goods = List<Good> goods =
await _dataService.getGoodsByBarcode(barcode: barcode); await _dataService.getGoodsByBarcode(barcode: barcode);
if (goods != null && goods.isNotEmpty) { if (goods != null && goods.isNotEmpty) {
Redux.store.dispatch(addProductToKassaItems(goods.first, dataMatrix)); await Redux.store.dispatch(addProductToKassaItems(goods.first, dataMatrix));
} else { } else {
_dialogService.showDialog( _dialogService.showDialog(
description: 'Товар не найден: $barcode'); description: 'Товар не найден: $barcode');
@ -238,33 +240,48 @@ class KassaTab extends StatelessWidget {
result.rawContent = 'Unknown error: $e'; result.rawContent = 'Unknown error: $e';
_dialogService.showDialog(description: 'Неизвестная ошибка: $e'); _dialogService.showDialog(description: 'Неизвестная ошибка: $e');
} }
} finally {
await Redux.store.dispatch(changePinSkipFromSetting(false));
} }
} }
void showModalBottomSheetCatalog(BuildContext context, String action) { void showModalBottomSheetCatalog(BuildContext context, String action) {
showModalBottomSheet(
context: context, if (action == 'add') {
isScrollControlled: true, Navigator.push(
backgroundColor: Colors.transparent, context,
builder: (context) { MaterialPageRoute(builder: (context) => ProductAddBottomSheet())
return DraggableScrollableSheet( );
initialChildSize: 0.8, } else {
maxChildSize: 0.95, Navigator.push(
minChildSize: 0.5, context,
builder: (BuildContext context, ScrollController scrollController) { MaterialPageRoute(builder: (context) => CatalogBottomSheet())
if (action == 'add') { );
return ProductAddBottomSheet( }
scrollController: scrollController,
); // showModalBottomSheet(
} else { // context: context,
return CatalogBottomSheet( // isScrollControlled: true,
scrollController: scrollController, // backgroundColor: Colors.transparent,
); // builder: (context) {
} // return DraggableScrollableSheet(
}, // initialChildSize: 0.8,
); // maxChildSize: 0.95,
}); // minChildSize: 0.5,
// builder: (BuildContext context, ScrollController scrollController) {
// if (action == 'add') {
// return ProductAddBottomSheet(
// scrollController: scrollController,
// );
// } else {
// return CatalogBottomSheet(
// scrollController: scrollController,
// );
// }
// },
// );
// });
} }
} }

View File

@ -51,7 +51,7 @@ class _ProductAddBottomSheetState extends State<ProductAddBottomSheet> {
), ),
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.only(top: 15, left: 10, right: 15), padding: EdgeInsets.only(top: 15, left: 10, right: 15, bottom: 0 ),
child: ListView( child: ListView(
controller: widget.scrollController, controller: widget.scrollController,
children: <Widget>[ children: <Widget>[
@ -78,7 +78,8 @@ class _ProductAddBottomSheetState extends State<ProductAddBottomSheet> {
decimal: false, decimal: false,
), ),
inputFormatters: <TextInputFormatter>[ inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly // WhitelistingTextInputFormatter.digitsOnly
FilteringTextInputFormatter.digitsOnly
], ],
controller: countController, controller: countController,
onChanged: calcOnChange, onChanged: calcOnChange,
@ -95,7 +96,7 @@ class _ProductAddBottomSheetState extends State<ProductAddBottomSheet> {
keyboardType: keyboardType:
const TextInputType.numberWithOptions(decimal: true), const TextInputType.numberWithOptions(decimal: true),
inputFormatters: <TextInputFormatter>[ inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter(RegExp("^[0-9.]*")), FilteringTextInputFormatter.allow(RegExp("^[0-9.]*")),
], ],
controller: priceController, controller: priceController,
onChanged: calcOnChange, onChanged: calcOnChange,

View File

@ -0,0 +1,79 @@
import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_lock_screen/flutter_lock_screen.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aman_kassa_flutter/core/locator.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
class PassCodeScreen extends StatefulWidget {
PassCodeScreen({Key key, this.title}) : super(key: key);
final String title;
@override
_PassCodeScreenState createState() => new _PassCodeScreenState();
}
class _PassCodeScreenState extends State<PassCodeScreen> {
// bool isFingerprint = false;
NavigatorService _navigatorService = locator<NavigatorService>();
final backgroundedTimeKey = 'backgroundedTimeKey';
// Future<Null> biometrics() async {
// final LocalAuthentication auth = new LocalAuthentication();
// bool authenticated = false;
//
// try {
// authenticated = await auth.authenticateWithBiometrics(
// localizedReason: 'Scan your fingerprint to authenticate',
// useErrorDialogs: true,
// stickyAuth: false);
// } on PlatformException catch (e) {
// print(e);
// }
// if (!mounted) return;
// if (authenticated) {
// setState(() {
// isFingerprint = true;
// });
// }
// }
@override
Widget build(BuildContext context) {
var myPass = [];
String _pinCode = Redux.store.state.settingState.pinCode;
for (var i = 0; i < _pinCode.length; i++) {
myPass.add(int.parse(_pinCode[i]));
}
return LockScreen(
title: "Введите ПИН-код",
passLength: myPass.length,
bgImage: "assets/images/secBg.jpg",
// fingerPrintImage: "assets/images/finger.png",
// showFingerPass: true,
// fingerFunction: biometrics,
// fingerVerify: isFingerprint,
borderColor: Colors.white,
showWrongPassDialog: true,
wrongPassContent: "Неверный код, повторите попытку",
wrongPassTitle: "Aman Kassa",
wrongPassCancelButtonText: "Отмена",
passCodeVerify: (passcode) async {
for (int i = 0; i < myPass.length; i++) {
if (passcode[i] != myPass[i]) {
return false;
}
}
return true;
},
onSuccess: () {
Redux.store.dispatch(changePinLockedFromSetting(false));
_navigatorService.replace(HomeViewRoute);
});
}
}

View File

@ -70,75 +70,79 @@ class _LoginViewState extends State<LoginView> {
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
backgroundColor: fillColor, backgroundColor: fillColor,
body: Padding( body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 50), physics: BouncingScrollPhysics(),
child: Column( child: Padding(
mainAxisSize: MainAxisSize.max, padding: const EdgeInsets.symmetric(horizontal: 50),
mainAxisAlignment: MainAxisAlignment.center, child: Column(
crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max,
children: <Widget>[ mainAxisAlignment: MainAxisAlignment.center,
Stack( crossAxisAlignment: CrossAxisAlignment.center,
alignment: Alignment.bottomLeft, children: <Widget>[
children: <Widget>[ verticalSpaceLarge,
SizedBox( Stack(
height: 150, alignment: Alignment.bottomLeft,
child: Image.asset('assets/images/logo.png'), children: <Widget>[
), SizedBox(
Positioned( height: 150,
child: Text( child: Image.asset('assets/images/logo.png'),
'онлайн касса',
style: TextStyle(fontWeight: FontWeight.bold),
), ),
bottom: 23.0, Positioned(
left: 25.0, child: Text(
), 'онлайн касса',
], style: TextStyle(fontWeight: FontWeight.bold),
), ),
bottom: 23.0,
left: 25.0,
),
],
),
InputField( InputField(
placeholder: 'Электронная почта', placeholder: 'Электронная почта',
controller: emailController, controller: emailController,
textInputType: TextInputType.emailAddress, textInputType: TextInputType.emailAddress,
nextFocusNode: passwordNode, nextFocusNode: passwordNode,
additionalNote: vm.loginFormMessage.email, additionalNote: vm.loginFormMessage.email,
), ),
verticalSpaceSmall, verticalSpaceSmall,
InputField( InputField(
placeholder: 'Пароль', placeholder: 'Пароль',
password: true, password: true,
controller: passwordController, controller: passwordController,
fieldFocusNode: passwordNode, fieldFocusNode: passwordNode,
additionalNote: vm.loginFormMessage.password, additionalNote: vm.loginFormMessage.password,
enterPressed: _pressBtnEnter, enterPressed: _pressBtnEnter,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
), ),
verticalSpaceMedium, verticalSpaceMedium,
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
SizedBox( SizedBox(
width: 150, width: 150,
child: BusyButton( child: BusyButton(
title: 'Войти', title: 'Войти',
busy: vm.isLoading, busy: vm.isLoading,
onPressed: _pressBtnEnter, onPressed: _pressBtnEnter,
), ),
) )
], ],
), ),
verticalSpaceLarge, verticalSpaceLarge,
// TextLink( // TextLink(
// 'Регистрация', // 'Регистрация',
// onPressed: () {}, // onPressed: () {},
// ), // ),
IconButton( IconButton(
icon: Icon(MdiIcons.qrcodeScan), icon: Icon(MdiIcons.qrcodeScan),
iconSize: 40, iconSize: 40,
tooltip: "Scan", tooltip: "Scan",
onPressed: scan, onPressed: scan,
) )
], ],
),
), ),
)); ));
}); });

View File

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

View File

@ -1,16 +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/locator.dart';
import 'package:aman_kassa_flutter/core/models/calc_model.dart'; import 'package:aman_kassa_flutter/core/models/calc_model.dart';
import 'package:aman_kassa_flutter/core/models/check_image_modal.dart';
import 'package:aman_kassa_flutter/core/models/card_data.dart';
import 'package:aman_kassa_flutter/core/models/product_dao.dart'; import 'package:aman_kassa_flutter/core/models/product_dao.dart';
import 'package:aman_kassa_flutter/core/models/response.dart'; import 'package:aman_kassa_flutter/core/models/response.dart';
import 'package:aman_kassa_flutter/core/route_names.dart'; import 'package:aman_kassa_flutter/core/route_names.dart';
import 'package:aman_kassa_flutter/core/services/BankService.dart';
import 'package:aman_kassa_flutter/core/services/DataService.dart'; import 'package:aman_kassa_flutter/core/services/DataService.dart';
import 'package:aman_kassa_flutter/core/services/dialog_service.dart'; import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
import 'package:aman_kassa_flutter/core/services/navigator_service.dart'; import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
import 'package:aman_kassa_flutter/redux/actions/calc_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/calc_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/kassa_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
import 'package:aman_kassa_flutter/redux/actions/user_actions.dart'; import 'package:aman_kassa_flutter/redux/actions/user_actions.dart';
import 'package:aman_kassa_flutter/redux/constants/operation_const.dart'; import 'package:aman_kassa_flutter/redux/constants/operation_const.dart';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart'; import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:aman_kassa_flutter/redux/state/bank_state.dart';
import 'package:aman_kassa_flutter/redux/state/calc_state.dart'; import 'package:aman_kassa_flutter/redux/state/calc_state.dart';
import 'package:aman_kassa_flutter/redux/state/kassa_state.dart'; import 'package:aman_kassa_flutter/redux/state/kassa_state.dart';
import 'package:aman_kassa_flutter/redux/store.dart'; import 'package:aman_kassa_flutter/redux/store.dart';
@ -22,6 +30,12 @@ import 'package:aman_kassa_flutter/widgets/fields/busy_button.dart';
import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart'; import 'package:aman_kassa_flutter/widgets/loader/Dialogs.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:aman_kassa_flutter/views/payment/halyk_pos_service.dart';
import '../../core/models/aman_dao.dart';
import '../../core/models/card_data.dart';
import '../../core/models/card_data.dart';
class PaymentView extends StatefulWidget { class PaymentView extends StatefulWidget {
final PaymentModel model; final PaymentModel model;
@ -36,13 +50,26 @@ class _PaymentViewState extends State<PaymentView> {
final GlobalKey<State> _keyLoader = new GlobalKey<State>(); final GlobalKey<State> _keyLoader = new GlobalKey<State>();
final DataService _dataService = locator<DataService>(); final DataService _dataService = locator<DataService>();
final DialogService _dialogService = locator<DialogService>(); final DialogService _dialogService = locator<DialogService>();
BankService _bankService = locator<BankService>();
final NavigatorService _navigatorService = locator<NavigatorService>(); final NavigatorService _navigatorService = locator<NavigatorService>();
bool isBusy; bool isBusy;
bool isBankApiAccess;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
isBusy = false; isBusy = false;
isBankApiAccess = false;
_bankInit();
}
_bankInit() async {
int version = await _bankService.version();
if (version >= _bankService.sdkVersion) {
setState(() {
isBankApiAccess = true;
});
}
} }
@override @override
@ -92,9 +119,10 @@ class _PaymentViewState extends State<PaymentView> {
String dataTitle() => String dataTitle() =>
widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат'; widget.model.operationType == OperationTypePay ? 'Оплата' : 'Возврат';
String dataText() => widget.model.operationType == OperationTypePay String dataText() =>
? 'К оплате' widget.model.operationType == OperationTypePay
: 'К возврату'; ? 'К оплате'
: 'К возврату';
StoreConnector buildStoreConnector() { StoreConnector buildStoreConnector() {
if (widget.model.mode == SettingModeCalc) { if (widget.model.mode == SettingModeCalc) {
@ -130,42 +158,139 @@ class _PaymentViewState extends State<PaymentView> {
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: BusyButton( child: BusyButton(
title: 'Оплатить картой', title: 'Оплатить картой',
onPressed: () { onPressed: () {
pressPayment('card'); pressPayment('card', null);
}, },
mainColor: greenColor, mainColor: primaryColor,
)), )),
horizontalSpaceSmall, horizontalSpaceSmall,
Expanded( Expanded(
child: BusyButton( child: BusyButton(
title: 'Наличными', title: 'Наличными',
onPressed: () { onPressed: () {
pressPayment('cash'); pressPayment('cash', null);
}, },
mainColor: primaryColor, mainColor: greenColor,
)), )),
], ],
), ),
), ),
verticalSpaceLarge, verticalSpaceLarge,
_nfsButtonRender(),
verticalSpaceSmall,
Expanded( Expanded(
child: Container(), child: Container(),
), ),
Container( Container(
child: BusyButton( child: BusyButton(
title: 'Отмена', title: 'Отмена',
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
mainColor: redColor, mainColor: redColor,
)), )),
], ],
), ),
); );
} }
pressPayment(String type) async { Widget _nfsButtonRender() {
if (!isBankApiAccess || widget.model.operationType != OperationTypePay) {
return Container();
}
return StoreConnector<AppState, AppState>(
converter: (store) => store.state,
builder: (_, _state) {
BankState state = _state.bankState;
double _total;
if (widget.model.mode == SettingModeCalc) {
String value = totalCalc(_state.calcState.calcItems);
_total = double.parse(value);
} else {
String value = totalKassa(_state.kassaState.kassaItems);
_total = double.parse(value);
}
if (state.password == null || state.login == null || state.password.length < 1 || state.login.length < 1) {
return Container();
}
return InkWell(
onTap: () async {
var today = new DateTime.now();
var yesterday = today.subtract(new Duration(days: 1));
if( Redux.store.state.userState == null
|| Redux.store.state.userState.smena == null
|| Redux.store.state.userState.smena.startedAt == null
|| yesterday.isAfter(Redux.store.state.userState.smena.startedAt)) {
_dialogService.showDialog(description: 'Текущая смена открыта более 24 ч. Необходимо закрыть смену и открыть ее заново.');
return;
}
try {
await Redux.store.dispatch(changePinSkipFromSetting(true));
AmanDao<CardData> data = await paymentHalykPos(_total);
if (data.success) {
pressPayment(widget.model.operationType, data.data);
} else {
_dialogService.showDialog(description: data.msg);
}
} finally {
await Redux.store.dispatch(changePinSkipFromSetting(false));
}
},
splashColor: halykColor.withOpacity(0.4),
borderRadius: BorderRadius.circular(10.0),
highlightColor: halykColor.withOpacity(0.1),
child: Container(
width: ScreenUtil().setSp(100.0),
padding: const EdgeInsets.symmetric(vertical: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0)
),
child: Column(
children: [
Container(
width: ScreenUtil().setSp(80.0),
height: ScreenUtil().setSp(80.0),
margin: const EdgeInsets.only(bottom: 8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(10.0),
image: DecorationImage(
image: AssetImage('assets/images/halykpos.png'), fit: BoxFit.fitWidth
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3), // changes position of shadow
),
],
),
),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(
// MdiIcons.nfc,
// color: halykColor,
// size: ScreenUtil().setSp(20.0),
// ),
// Text('Tap2Phone',style: TextStyle(fontSize: ScreenUtil().setSp(10.0), color: halykColor, fontWeight: FontWeight.bold ),),
// ],
// ),
],
),
),
);
}
);
}
pressPayment(String type, CardData cardData) async {
setState(() { setState(() {
isBusy = true; isBusy = true;
}); });
@ -187,14 +312,17 @@ class _PaymentViewState extends State<PaymentView> {
operationType: widget.model.operationType, operationType: widget.model.operationType,
tradeType: _tradeType, tradeType: _tradeType,
calcItems: calcItems, calcItems: calcItems,
mode: _mode); mode: _mode,
cardData: cardData
);
setState(() { setState(() {
isBusy = false; isBusy = false;
}); });
if( response != null) { if (response != null) {
if (response.operation) { if (response.operation) {
String message = response.body['message']; String message = response.body['message'];
String check = response.body['check']; String check = response.body['check'];
var checkText = response.body['check_text'];
String url = response?.body['link']; String url = response?.body['link'];
print('url : $url'); print('url : $url');
if (_mode == SettingModeCalc) { if (_mode == SettingModeCalc) {
@ -207,24 +335,26 @@ class _PaymentViewState extends State<PaymentView> {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_navigatorService.pop(); _navigatorService.pop();
_navigatorService.push(ImageShowRoute, _navigatorService.push(ImageShowRoute,
arguments: ImageShowModel(data:check, title: message, url: url )); arguments: ImageShowModel(data: new CheckImageModal(
} else if (!response.operation && ![401,402,403,412,500].contains(response.status)) { base64Data: check, textData: checkText != null ? jsonEncode(checkText) : null),
title: message,
url: url));
} else if (!response.operation && ![401, 402, 403, 412, 500].contains(response.status)) {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']); _dialogService.showDialog(description: response.body['message']);
} else if(!response.operation && response.body['message'] != null) { } else if (!response.operation && response.body['message'] != null) {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
_dialogService.showDialog(description: response.body['message']); _dialogService.showDialog(description: response.body['message']);
} else { } else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} }
} else { } else {
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} }
} catch (e) { } catch (e) {
print(e); print(e);
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop(); Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
} finally { } finally {
//Navigator.of(context, rootNavigator: true).pop(); //Navigator.of(context, rootNavigator: true).pop();
setState(() { setState(() {
isBusy = false; isBusy = false;
@ -258,5 +388,8 @@ class _PaymentViewState extends State<PaymentView> {
class PaymentModel { class PaymentModel {
String operationType; String operationType;
String mode; String mode;
PaymentModel({this.mode, this.operationType}); Voucher voucher;
CardData cardData;
PaymentModel({this.mode, this.operationType, this.voucher, this.cardData});
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,7 +27,7 @@ class _QrViewState extends State<QrView> {
body: Container( body: Container(
child: Center( child: Center(
child: QrImage( child: QrImage(
data: widget.data.data, data: widget.data.url,
version: QrVersions.auto, version: QrVersions.auto,
size: 220.0, size: 220.0,
), ),

View File

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
class SettingItem extends StatefulWidget {
final String name;
final String value;
final String title;
final Function onTap;
SettingItem({Key key, this.name, this.value, this.onTap, this.title }) : super(key: key);
@override
_SettingItemState createState() => _SettingItemState();
}
class _SettingItemState extends State<SettingItem> {
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
title: Text(widget.title),
subtitle: Text.rich(
TextSpan(
text: widget.name,
style: TextStyle(fontWeight: FontWeight.w500),
children: <TextSpan>[
if(widget.value !=null)
TextSpan(text: ' ${widget.value}', style: TextStyle(fontStyle: FontStyle.italic)),
],
)
),
trailing: Icon(Icons.chevron_right),
onTap: widget.onTap,
),
);
}
}

View File

@ -0,0 +1,234 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
import 'package:charset_converter/charset_converter.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as Im;
import 'package:path_provider/path_provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
Future<Ticket> testTicket(PaperSize paper) async {
final Ticket ticket = Ticket(paper);
//Uint8List encTxt11 = await CharsetConverter.encode("cp866", "Russian: Привет Мир!");
//ticket.textEncoded(encTxt11, styles: PosStyles(codeTable: PosCodeTable.pc866_2));
//ticket.textEncoded(encTxt11);
// ticket.text('Special 1: àÀ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //А
// ticket.text('Special 1: á'.toUpperCase(), styles: PosStyles(codeTable: PosCodeTable.westEur));// Б
// ticket.text('Special 1: â', styles: PosStyles(codeTable: PosCodeTable.westEur)); //В
// ticket.text('Special 1: ã', styles: PosStyles(codeTable: PosCodeTable.westEur));// Г
// ticket.text('Special 1: äÄ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Д
// ticket.text('Special 1: å', styles: PosStyles(codeTable: PosCodeTable.westEur));// Е
// ticket.text('Special 1: æÆ', styles: PosStyles(codeTable: PosCodeTable.westEur));// Ж
// ticket.text('Special 1: ç', styles: PosStyles(codeTable: PosCodeTable.westEur));//З
// ticket.text('Special 1: èÈ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // И
// ticket.text('Special 1: éÉ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Й
// ticket.text('Special 1: ê', styles: PosStyles(codeTable: PosCodeTable.westEur));//К
// ticket.text('Special 1: ëË', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Л
// ticket.text('Special 1: ìÌ', styles: PosStyles(codeTable: PosCodeTable.westEur));// M
// ticket.text('Special 1: íÍ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Н
// ticket.text('Special 1: î', styles: PosStyles(codeTable: PosCodeTable.westEur));// О
// ticket.text('Special 1: ï', styles: PosStyles(codeTable: PosCodeTable.westEur)); // П
// ticket.text('Special 1: ð', styles: PosStyles(codeTable: PosCodeTable.westEur));// Р
// ticket.text('Special 1: ñ', styles: PosStyles(codeTable: PosCodeTable.westEur));// С
// ticket.text('Special 1: ò', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Т
// ticket.text('Special 1: óÓ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //У
// ticket.text('Special 1: ô', styles: PosStyles(codeTable: PosCodeTable.westEur));// Ф
// ticket.text('Special 1: õÕ', styles: PosStyles(codeTable: PosCodeTable.westEur));// Х
// ticket.text('Special 1: ö', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ц
// ticket.text('Special 1: ÷', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ч
// ticket.text('Special 1: ø', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ш
// ticket.text('Special 1: ù', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Щ
// ticket.text('Special 1: ú', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ъ
// ticket.text('Special 1: û', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ы
// ticket.text('Special 1: üÜ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ь
// ticket.text('Special 1: ý', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Э
// ticket.text('Special 1: þ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // ю
// ticket.text('Special 1: ÿß', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Я
// Uint8List encTxt11 = await CharsetConverter.encode("cp866", "Russian: Привет Мир!");
// //ticket.textEncoded(encTxt11, styles: PosStyles(codeTable: PosCodeTable.pc866_2));
// ticket.textEncoded(encTxt11);
ticket.text(
'Regular: aA bB cC dD eE fF gG hH iI jJ kK lL mM nN oO pP qQ rR sS tT uU vV wW xX yY zZ');
//ticket.text('Special 1: àÀ èÈ éÉ ûÛ üÜ çÇ ôÔ', styles: PosStyles(codeTable: PosCodeTable.westEur));
//ticket.text('Special 2: blåbærgrød', styles: PosStyles(codeTable: PosCodeTable.westEur));
ticket.text('Bold text', styles: PosStyles(bold: true));
ticket.text('Reverse text', styles: PosStyles(reverse: true));
ticket.text('Underlined text',
styles: PosStyles(underline: true), linesAfter: 1);
ticket.text('Align left', styles: PosStyles(align: PosAlign.left));
ticket.text('Align center', styles: PosStyles(align: PosAlign.center));
ticket.text('Align right',
styles: PosStyles(align: PosAlign.right), linesAfter: 1);
ticket.row([
PosColumn(
text: 'col3',
width: 3,
styles: PosStyles(align: PosAlign.center, underline: true),
),
PosColumn(
text: 'col6',
width: 6,
styles: PosStyles(align: PosAlign.center, underline: true),
),
PosColumn(
text: 'col3',
width: 3,
styles: PosStyles(align: PosAlign.center, underline: true),
),
]);
ticket.text('Text size 200%',
styles: PosStyles(
height: PosTextSize.size2,
width: PosTextSize.size2,
));
// Print image
//final ByteData data = await rootBundle.load('assets/images/logo.png');
//final Uint8List bytes = data.buffer.asUint8List();
// Print image using alternative commands
// ticket.imageRaster(image);
// ticket.imageRaster(image, imageFn: PosImageFn.graphics);
// Print barcode
final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
ticket.barcode(Barcode.upcA(barData));
ticket.feed(2);
ticket.cut();
return ticket;
}
Future<Ticket> testTicketImage(PaperSize paper) async {
final Ticket ticket = Ticket(paper);
// Print image
final ByteData byteData = await rootBundle.load('assets/images/check.png');
final Uint8List bytes = byteData.buffer.asUint8List();
final Im.Image image = Im.decodeImage(bytes);
// Using `ESC *`
//ticket.image(imagea);
// Using `GS v 0` (obsolete)
//ticket.imageRaster(imagea);
// Using `GS ( L`
ticket.imageRaster(image, imageFn: PosImageFn.bitImageRaster);
//ticket.image(imagea);
ticket.feed(2);
ticket.cut();
return ticket;
}
Future<Ticket> printImageCheck(PaperSize paper, String base64Src) async {
final Ticket ticket = Ticket(paper);
final Uint8List bytes = base64Decode(base64Src);
final Im.Image image = Im.decodeImage(bytes);
ticket.imageRaster(image, imageFn: PosImageFn.bitImageRaster);
//ticket.image(image);
ticket.feed(2);
ticket.cut();
return ticket;
}
Future<Ticket> printTextCheck(PaperSize paper, String encoding, var data ) async {
final Ticket ticket = Ticket(paper);
ticket.emptyLines(1);
PosCodeTable codeTable;
if(encoding == SettingPrinterEncodingCp866) {
codeTable = PosCodeTable.pc866_2;
} else if(encoding == SettingPrinterEncodingWin1251) {
codeTable = PosCodeTable.wpc1251;
}
//ticket.setGlobalCodeTable(codeTable);
ticket.setGlobalFont(PosFontType.fontB);
String qr = data['qr'];
List<dynamic> rows = data['rows'] as List;
for(dynamic element in rows) {
var text = element['text'];
int size = element['size'] as int;
bool center = element['center'] !=null ? element['center'] as bool : false;
if(text is List) {
Uint8List firstCol = await CharsetConverter.encode(encoding, (text).first as String);
Uint8List lastCol = await CharsetConverter.encode(encoding, (text).last as String);
ticket.row([
PosColumn(
textEncoded: firstCol,
width: 6,
styles: PosStyles(align: PosAlign.left, codeTable: codeTable ),
),
PosColumn(
textEncoded: lastCol,
width: 6,
styles: PosStyles(align: PosAlign.right, codeTable: codeTable ),
),
]);
} else {
String line = text as String;
if(line == 'breakline') {
ticket.hr();
} else if(line == 'br') {
ticket.emptyLines(1);
} else if(line.trim() == '') {
ticket.emptyLines(1);
} else {
line = line.replaceAll("«", '\"');
line = line.replaceAll("»", '\"');
Uint8List encTxt11 = await CharsetConverter.encode(encoding, line);
ticket.textEncoded( encTxt11, styles: PosStyles( align: center ? PosAlign.center : PosAlign.left, codeTable: codeTable ));
}
}
}
// Print barcode
//final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
//ticket.barcode(Barcode.upcA(barData));
//ticket.qrcode(qr, align: PosAlign.center);
ticket.emptyLines(1);
const double qrSize = 200;
try {
final uiImg = await QrPainter(
data: qr,
version: QrVersions.auto,
gapless: true,
).toImageData(qrSize);
//final dir = await getTemporaryDirectory();
//final pathName = '${dir.path}/qr_tmp.png';
//final qrFile = File(pathName);
//final imgFile = await qrFile.writeAsBytes(uiImg.buffer.asUint8List());
final img = Im.decodePng(uiImg.buffer.asUint8List());
ticket.image(img);
//ticket.qrcode(qr, size: QRSize.Size1 );
} catch (e) {
print(e);
}
ticket.emptyLines(1);
ticket.feed(1);
ticket.cut();
return ticket;
}

View File

@ -0,0 +1,12 @@
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
var encoding = {
SettingPrinterEncodingCp866: "CP-866",
SettingPrinterEncodingWin1251: "Windows-1251",
SettingPrinterEncodingImage: "Big-Encoding",
};
var paperSize = {
SettingPrinterPaperM58: "58 мм",
SettingPrinterPaperM80: "80 мм"
};

View File

@ -0,0 +1,53 @@
var exampleJson = {
"check_text": {
"rows": [
{"size": 14, "text": "", "center": true},
{"size": 15, "text": "breakline", "center": true},
{"size": 14, "text": "ТОО «Aman Systems»"},
{"size": 14, "text": "ИИН/БИН: 180640018960"},
{"size": 14, "text": "Сер. номер ККМ: TEST00000005"},
{"size": 14, "text": "Регистрационный номер: 123132132323"},
{"size": 14, "text": "Коргальджинское шоссе, д.19 оф.308"},
{"size": 15, "text": "breakline", "center": true},
{"size": 14, "text": "Продажа,Наличные, ", "center": true},
{"size": 15, "text": "ФИСКАЛЬНЫЙ ЧЕК №16580", "center": true},
{"size": 15, "text": "ФП 471369529060", "center": true},
{"size": 15, "text": "Дата: 03.03.2021 23:16", "center": true},
{"size": 15, "text": "breakline", "center": true},
{"size": 14, "text": "Кассир: Амантай ИХ"},
{"size": 14, "text": "Касса: Касса 1"},
{"size": 15, "text": "breakline", "center": true},
{"size": 15, "text": "br"},
{"size": 14, "text": "1. test"},
{"size": 14, "text": "200,00 x 1 = 200,00"},
{"size": 10, "text": "br"},
{"size": 15, "text": "breakline"},
{
"size": 17,
"text": ["ИТОГО:", "200,00"]
},
{
"size": 14,
"text": ["Наличные", "200,00"]
},
{"size": 15, "text": "breakline"},
{"size": 17, "text": "В том числе НДС:"},
{
"size": 14,
"text": ["12 %", "21,43"]
},
{"size": 14, "text": ""},
{"size": 15, "text": "breakline"},
{"size": 15, "text": "ОФД АО \"Транстелеком\"", "center": true},
{"size": 15, "text": "ofd1.kz", "center": true},
{"size": 14, "text": ""},
{"size": 15, "text": "breakline"},
{"size": 14, "text": "", "center": true},
{"size": 13, "text": "порядковый номер чека:19800", "center": true},
{"size": 14, "text": "Онлайн касса Aman", "center": true},
{"size": 14, "text": "kassa.aman.com.kz", "center": true}
],
"qr":
"87.255.215.94:4000/t/?i=471369529060&f=123132132323&s=200.0&t=20210303T231651"
}
};

Some files were not shown because too many files have changed in this diff Show More