receipt print release
parent
ae272604b6
commit
1a9958e84f
|
|
@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
compileSdkVersion 31
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
|
@ -53,7 +53,7 @@ android {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "kz.com.aman.satu"
|
applicationId "kz.com.aman.satu"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 31
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
// multiDexEnabled true
|
// multiDexEnabled true
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:satu/core/utils/utils_parse.dart';
|
||||||
|
|
||||||
const String goodTableName = 'goods';
|
const String goodTableName = 'goods';
|
||||||
const String GoodColumnId = 'id';
|
const String GoodColumnId = 'id';
|
||||||
const String GoodColumnCategoryId = 'category_id';
|
const String GoodColumnCategoryId = 'category_id';
|
||||||
|
|
@ -22,7 +24,7 @@ class Good {
|
||||||
ean = map[GoodColumnEan] as String;
|
ean = map[GoodColumnEan] as String;
|
||||||
appCompanyId = map[GoodColumnAppCompanyId] as int;
|
appCompanyId = map[GoodColumnAppCompanyId] as int;
|
||||||
optPrice = map[GoodColumnOptPrice] as num;
|
optPrice = map[GoodColumnOptPrice] as num;
|
||||||
basePrice = map[GoodColumnBasePrice] as num;
|
basePrice = cast<num>(map[GoodColumnBasePrice]);
|
||||||
divisible = map[GoodColumnDivisible] as int;
|
divisible = map[GoodColumnDivisible] as int;
|
||||||
updatedAt = map[GoodColumnUpdatedAt] as String;
|
updatedAt = map[GoodColumnUpdatedAt] as String;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class DataService extends BaseService {
|
||||||
|
|
||||||
final DialogService _dialogService = locator<DialogService>();
|
final DialogService _dialogService = locator<DialogService>();
|
||||||
|
|
||||||
Future<bool> sellBtnHandler(
|
Future<TransactionData?> sellBtnHandler(
|
||||||
{double card = 0, double nal = 0, double total = 0}) async {
|
{double card = 0, double nal = 0, double total = 0}) async {
|
||||||
final SellRequest request = SellRequest();
|
final SellRequest request = SellRequest();
|
||||||
final SellState sellState = Redux.store!.state.sellState!;
|
final SellState sellState = Redux.store!.state.sellState!;
|
||||||
|
|
@ -46,9 +46,9 @@ class DataService extends BaseService {
|
||||||
final SellResponse response = await _api.sell(request);
|
final SellResponse response = await _api.sell(request);
|
||||||
if (response.operation == false) {
|
if (response.operation == false) {
|
||||||
_dialogService.showDialog(description: response.message);
|
_dialogService.showDialog(description: response.message);
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
await _updateTransaction(
|
final TransactionData transactionData = await _updateTransaction(
|
||||||
transactionState: transactionState,
|
transactionState: transactionState,
|
||||||
total: total,
|
total: total,
|
||||||
card: card,
|
card: card,
|
||||||
|
|
@ -56,10 +56,10 @@ class DataService extends BaseService {
|
||||||
sellResponse: response);
|
sellResponse: response);
|
||||||
|
|
||||||
await Redux.store!.dispatch(loadSellData);
|
await Redux.store!.dispatch(loadSellData);
|
||||||
return true;
|
return transactionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateTransaction(
|
Future<TransactionData> _updateTransaction(
|
||||||
{required TransactionState transactionState,
|
{required TransactionState transactionState,
|
||||||
required double card,
|
required double card,
|
||||||
required double nal,
|
required double nal,
|
||||||
|
|
@ -83,6 +83,7 @@ class DataService extends BaseService {
|
||||||
transaction.data = jsonEncode(data.toMap());
|
transaction.data = jsonEncode(data.toMap());
|
||||||
log.i(jsonEncode(data.toMap()));
|
log.i(jsonEncode(data.toMap()));
|
||||||
await _db.update(transactionTableName, transaction.toMap());
|
await _db.update(transactionTableName, transaction.toMap());
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemBean _productToItemBean(ProductDao product) {
|
ItemBean _productToItemBean(ProductDao product) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:charset_converter/charset_converter.dart';
|
import 'package:charset_converter/charset_converter.dart';
|
||||||
|
|
@ -5,81 +6,149 @@ import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
|
||||||
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart';
|
import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart';
|
||||||
import 'package:image/image.dart';
|
import 'package:image/image.dart' as Im;
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:satu/core/models/flow/check_bean.dart';
|
||||||
|
import 'package:satu/core/models/flow/check_row_bean.dart';
|
||||||
import 'package:satu/core/models/settings/printer_setting.dart';
|
import 'package:satu/core/models/settings/printer_setting.dart';
|
||||||
|
|
||||||
Future<List<int>> getReceipt(String encoding, String paperSize) async {
|
Future<List<int>> getTestReceipt(String encoding, String paperSize) async {
|
||||||
|
final CheckBean checkBean = CheckBean();
|
||||||
|
final CheckRowBean rowBean1 = CheckRowBean();
|
||||||
|
rowBean1.text = 'Тестовый чек';
|
||||||
|
rowBean1.center = true;
|
||||||
|
|
||||||
|
final CheckRowBean rowBean2 = CheckRowBean();
|
||||||
|
rowBean2.text = ['Левая сторона', 'Правая сторона'];
|
||||||
|
rowBean2.center = true;
|
||||||
|
|
||||||
|
checkBean.rows.add(rowBean1);
|
||||||
|
checkBean.rows.add(CheckRowBean()..text='{br}'..center=true);
|
||||||
|
checkBean.rows.add(CheckRowBean()..text='{line}'..center=true);
|
||||||
|
checkBean.rows.add(CheckRowBean()..text='{br}'..center=true);
|
||||||
|
checkBean.rows.add(rowBean2);
|
||||||
|
checkBean.rows.add(CheckRowBean()..text='{br}'..center=true);
|
||||||
|
checkBean.rows.add(CheckRowBean()..text='{line}'..center=true);
|
||||||
|
checkBean.qr = 'test qr data';
|
||||||
|
|
||||||
|
|
||||||
|
return await _generateReceipt(encoding, paperSize, checkBean);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> getReceipt(
|
||||||
|
String encoding, String paperSize, CheckBean checkBean) async {
|
||||||
|
return await _generateReceipt(encoding, paperSize, checkBean);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> _generateReceipt(
|
||||||
|
String encoding, String paperSize, CheckBean checkBean) async {
|
||||||
|
List<int> bytes = [];
|
||||||
final profile = await CapabilityProfile.load();
|
final profile = await CapabilityProfile.load();
|
||||||
final generator = Generator(
|
final generator = Generator(
|
||||||
paperSize == PrinterConst.paperSize58mm ? PaperSize.mm58 : PaperSize.mm80,
|
paperSize == PrinterConst.paperSize58mm ? PaperSize.mm58 : PaperSize.mm80,
|
||||||
profile,
|
profile,
|
||||||
);
|
);
|
||||||
|
|
||||||
String codeTable = 'CP866';
|
String codeTable = 'CP866';
|
||||||
if (encoding == PrinterConst.encodingCP866) {
|
if (encoding == PrinterConst.encodingCP866) {
|
||||||
codeTable = 'CP866';
|
codeTable = 'CP866';
|
||||||
} else if (encoding == PrinterConst.encodingCP1251) {
|
} else if (encoding == PrinterConst.encodingCP1251) {
|
||||||
codeTable = 'CP1251';
|
codeTable = 'CP1251';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<int> bytes = [];
|
|
||||||
generator.setGlobalCodeTable(codeTable);
|
generator.setGlobalCodeTable(codeTable);
|
||||||
|
|
||||||
|
for (CheckRowBean row in checkBean.rows) {
|
||||||
|
String type = row.text.runtimeType.toString();
|
||||||
|
final bool isList = type == 'List<dynamic>' || type == 'List<String>';
|
||||||
|
final bool isNull = type == 'Null';
|
||||||
|
final bool isString = type == 'String';
|
||||||
|
final bool center = row.center;
|
||||||
|
|
||||||
|
if (isNull) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isString) {
|
||||||
|
String text = row.text as String;
|
||||||
|
text = text.replaceAll('«', '«');
|
||||||
|
text = text.replaceAll('»', '»');
|
||||||
|
final bool isLine = '{line}' == text;
|
||||||
|
final bool isBr = '{br}' == text;
|
||||||
|
if (isBr) {
|
||||||
|
bytes += generator.feed(1);
|
||||||
|
} else if (isLine) {
|
||||||
|
bytes += generator.hr();
|
||||||
|
} else {
|
||||||
final Uint8List firstCol =
|
final Uint8List firstCol =
|
||||||
await CharsetConverter.encode(encoding.toLowerCase(), 'Тестовый чек');
|
await CharsetConverter.encode(encoding.toLowerCase(), text);
|
||||||
bytes += generator.textEncoded(firstCol);
|
bytes += generator.textEncoded(firstCol,
|
||||||
|
styles: PosStyles(align: center ? PosAlign.center : PosAlign.left));
|
||||||
bytes +=
|
}
|
||||||
generator.text('CENTER', styles: const PosStyles(align: PosAlign.center));
|
}
|
||||||
bytes += generator.text('Right',
|
|
||||||
styles: const PosStyles(align: PosAlign.right), linesAfter: 1);
|
|
||||||
|
|
||||||
|
if (isList) {
|
||||||
|
final List<dynamic> list = row.text as List<dynamic>;
|
||||||
|
if (list.length == 2) {
|
||||||
|
final Uint8List firstCol = await CharsetConverter.encode(
|
||||||
|
encoding.toLowerCase(), list[0] as String);
|
||||||
|
final Uint8List secondCol = await CharsetConverter.encode(
|
||||||
|
encoding.toLowerCase(), list[1] as String);
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: 'col3',
|
textEncoded: firstCol,
|
||||||
width: 3,
|
|
||||||
styles: const PosStyles(align: PosAlign.center, underline: true),
|
|
||||||
),
|
|
||||||
PosColumn(
|
|
||||||
text: 'col6',
|
|
||||||
width: 6,
|
width: 6,
|
||||||
styles: const PosStyles(align: PosAlign.center, underline: true),
|
styles: const PosStyles(align: PosAlign.left, underline: true),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: 'col3',
|
textEncoded: secondCol,
|
||||||
width: 3,
|
width: 6,
|
||||||
styles: const PosStyles(align: PosAlign.center, underline: true),
|
styles: const PosStyles(align: PosAlign.right, underline: true),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bytes += generator.text(
|
print('${row.text.runtimeType}, ${row.text}');
|
||||||
'Text size 200%',
|
}
|
||||||
styles: const PosStyles(
|
if (checkBean.qr != null) {
|
||||||
height: PosTextSize.size2,
|
bytes += generator.feed(2);
|
||||||
width: PosTextSize.size2,
|
const double qrSize = 200;
|
||||||
),
|
try {
|
||||||
);
|
final ByteData? uiImg = await QrPainter(
|
||||||
|
data: checkBean.qr!,
|
||||||
|
version: QrVersions.auto,
|
||||||
|
gapless: true,
|
||||||
|
).toImageData(qrSize);
|
||||||
|
final img = Im.decodePng(uiImg!.buffer.asUint8List());
|
||||||
|
bytes += generator.image(img!);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
|
||||||
// Print barcode
|
}
|
||||||
final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
|
|
||||||
bytes += generator.barcode(Barcode.upcA(barData));
|
|
||||||
|
|
||||||
bytes += generator.feed(2);
|
bytes += generator.feed(2);
|
||||||
bytes += generator.cut();
|
bytes += generator.cut();
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<int>> getReceiptImg(String paperSize) async {
|
Future<List<int>> getTestReceiptImg(String paperSize) async {
|
||||||
|
final ByteData data =
|
||||||
|
await rootBundle.load('assets/images/aman_kassa_check.png');
|
||||||
|
final Uint8List imgBytes = data.buffer.asUint8List();
|
||||||
|
return _getReceiptImg(paperSize, imgBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> getReceiptImg(String paperSize, Uint8List imgBytes) async {
|
||||||
|
return _getReceiptImg(paperSize, imgBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> _getReceiptImg(String paperSize, Uint8List imgBytes) async {
|
||||||
final profile = await CapabilityProfile.load();
|
final profile = await CapabilityProfile.load();
|
||||||
final generator = Generator(
|
final generator = Generator(
|
||||||
paperSize == PrinterConst.paperSize58mm ? PaperSize.mm58 : PaperSize.mm80,
|
paperSize == PrinterConst.paperSize58mm ? PaperSize.mm58 : PaperSize.mm80,
|
||||||
profile,
|
profile,
|
||||||
);
|
);
|
||||||
List<int> bytes = [];
|
List<int> bytes = [];
|
||||||
final ByteData data =
|
final Im.Image? image = Im.decodeImage(imgBytes);
|
||||||
await rootBundle.load('assets/images/aman_kassa_check.png');
|
|
||||||
final Uint8List imgBytes = data.buffer.asUint8List();
|
|
||||||
final Image? image = decodeImage(imgBytes);
|
|
||||||
// Using `ESC *`
|
// Using `ESC *`
|
||||||
bytes += generator.image(image!);
|
bytes += generator.image(image!);
|
||||||
bytes += generator.feed(2);
|
bytes += generator.feed(2);
|
||||||
|
|
@ -87,6 +156,22 @@ Future<List<int>> getReceiptImg(String paperSize) async {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getChunkSize() {
|
||||||
|
final bool isIos = Platform.isIOS;
|
||||||
|
if (isIos) {
|
||||||
|
return 75;
|
||||||
|
}
|
||||||
|
return 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getQueueSleep() {
|
||||||
|
final bool isIos = Platform.isIOS;
|
||||||
|
if (isIos) {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
BluetoothDevice printerDeviceToBluetoothDevice(PrinterDevice device) {
|
BluetoothDevice printerDeviceToBluetoothDevice(PrinterDevice device) {
|
||||||
return BluetoothDevice()
|
return BluetoothDevice()
|
||||||
..name = device.name
|
..name = device.name
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class _PrinterViewState extends State<PrinterView> {
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void printTest() async {
|
void print() async {
|
||||||
setState(() {
|
setState(() {
|
||||||
printerLocked = true;
|
printerLocked = true;
|
||||||
});
|
});
|
||||||
|
|
@ -45,40 +45,29 @@ class _PrinterViewState extends State<PrinterView> {
|
||||||
printerDeviceToBluetoothDevice(printerSetting.device!),
|
printerDeviceToBluetoothDevice(printerSetting.device!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
final int chunkSizeBytes = getChunkSize();
|
||||||
|
final int queueSleepTimeMs = getQueueSleep();
|
||||||
|
|
||||||
bool isIos = Platform.isIOS;
|
List<int> data = List.empty();
|
||||||
int chunkSizeBytes = 3096;
|
|
||||||
int queueSleepTimeMs = 100;
|
|
||||||
|
|
||||||
if (isIos) {
|
|
||||||
chunkSizeBytes = 75;
|
|
||||||
queueSleepTimeMs = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PrinterConst.encodingBigEncoding == printerSetting.encoding) {
|
if (PrinterConst.encodingBigEncoding == printerSetting.encoding) {
|
||||||
PosPrintResult printResult = await printerManager.writeBytes(
|
data = await getTestReceiptImg(
|
||||||
await getReceiptImg(
|
|
||||||
printerSetting.paperSize!,
|
printerSetting.paperSize!,
|
||||||
),
|
|
||||||
chunkSizeBytes: chunkSizeBytes,
|
|
||||||
queueSleepTimeMs: queueSleepTimeMs,
|
|
||||||
);
|
);
|
||||||
if(printResult.value != 1) {
|
|
||||||
_dialogService.showDialog(description: printResult.msg);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
PosPrintResult printResult = await printerManager.writeBytes(
|
data = await getTestReceipt(
|
||||||
await getReceipt(
|
|
||||||
printerSetting.encoding!,
|
printerSetting.encoding!,
|
||||||
printerSetting.paperSize!,
|
printerSetting.paperSize!,
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final PosPrintResult printResult = await printerManager.writeBytes(
|
||||||
|
data,
|
||||||
chunkSizeBytes: chunkSizeBytes,
|
chunkSizeBytes: chunkSizeBytes,
|
||||||
queueSleepTimeMs: queueSleepTimeMs,
|
queueSleepTimeMs: queueSleepTimeMs,
|
||||||
);
|
);
|
||||||
if (printResult.value != 1) {
|
if (printResult.value != 1) {
|
||||||
_dialogService.showDialog(description: printResult.msg);
|
_dialogService.showDialog(description: printResult.msg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
await Future.delayed(const Duration(seconds: 7));
|
await Future.delayed(const Duration(seconds: 7));
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -99,7 +88,7 @@ class _PrinterViewState extends State<PrinterView> {
|
||||||
final bool success =
|
final bool success =
|
||||||
snapshot.device != null && printerLocked == false;
|
snapshot.device != null && printerLocked == false;
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: success ? printTest : null,
|
onPressed: success ? print : null,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.print,
|
Icons.print,
|
||||||
color: success ? textColor : placeholderColor,
|
color: success ? textColor : placeholderColor,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.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:satu/core/models/entity_data/transaction_data.dart';
|
||||||
import 'package:satu/core/redux/state/sell_state.dart';
|
import 'package:satu/core/redux/state/sell_state.dart';
|
||||||
import 'package:satu/core/redux/store.dart';
|
import 'package:satu/core/redux/store.dart';
|
||||||
import 'package:satu/core/services/navigator_service.dart';
|
import 'package:satu/core/services/navigator_service.dart';
|
||||||
import 'package:satu/core/utils/locator.dart';
|
import 'package:satu/core/utils/locator.dart';
|
||||||
import 'package:satu/core/utils/utils_parse.dart';
|
import 'package:satu/core/utils/utils_parse.dart';
|
||||||
|
import 'package:satu/routes/route_names.dart';
|
||||||
import 'package:satu/shared/app_colors.dart';
|
import 'package:satu/shared/app_colors.dart';
|
||||||
import 'package:satu/core/services/data_service.dart';
|
import 'package:satu/core/services/data_service.dart';
|
||||||
import 'package:satu/views/work/views/payment/component/combine_dock.dart';
|
import 'package:satu/views/work/views/payment/component/combine_dock.dart';
|
||||||
|
|
@ -135,7 +137,10 @@ class _PaymentViewState extends State<PaymentView> {
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 45, vertical: 30),
|
const EdgeInsets.symmetric(horizontal: 45, vertical: 30),
|
||||||
child: BusyButton(
|
child: BusyButton(
|
||||||
title: 'ОПЛАТА', busy: loading, onPressed: _payment),
|
title: 'ОПЛАТА',
|
||||||
|
busy: loading,
|
||||||
|
onPressed: _payment,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -161,10 +166,11 @@ class _PaymentViewState extends State<PaymentView> {
|
||||||
nal = _cashSum;
|
nal = _cashSum;
|
||||||
}
|
}
|
||||||
|
|
||||||
final bool result =
|
final TransactionData? transactionData =
|
||||||
await _dataService.sellBtnHandler(card: card, nal: nal, total: _sum);
|
await _dataService.sellBtnHandler(card: card, nal: nal, total: _sum);
|
||||||
if(result) {
|
if (transactionData !=null) {
|
||||||
_navigatorService.pop();
|
_navigatorService.pop();
|
||||||
|
_navigatorService.push(receiptViewRoute, arguments: transactionData);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:satu/core/models/entity_data/transaction_data.dart';
|
import 'package:satu/core/models/entity_data/transaction_data.dart';
|
||||||
import 'package:satu/core/models/flow/sell_response.dart';
|
import 'package:satu/core/models/flow/sell_response.dart';
|
||||||
|
import 'package:satu/core/models/settings/printer_setting.dart';
|
||||||
|
import 'package:satu/core/redux/store.dart';
|
||||||
|
import 'package:satu/core/services/dialog_service.dart';
|
||||||
|
import 'package:satu/core/utils/locator.dart';
|
||||||
|
import 'package:satu/core/utils/pos_printer.dart';
|
||||||
import 'package:satu/shared/app_colors.dart';
|
import 'package:satu/shared/app_colors.dart';
|
||||||
import 'package:satu/widgets/bar/products_app_bar.dart';
|
import 'package:satu/widgets/bar/products_app_bar.dart';
|
||||||
|
|
||||||
class ReceiptView extends StatelessWidget {
|
class ReceiptView extends StatefulWidget {
|
||||||
const ReceiptView({
|
const ReceiptView({
|
||||||
required this.transactionData,
|
required this.transactionData,
|
||||||
Key? key,
|
Key? key,
|
||||||
|
|
@ -14,23 +22,106 @@ class ReceiptView extends StatelessWidget {
|
||||||
|
|
||||||
final TransactionData transactionData;
|
final TransactionData transactionData;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ReceiptView> createState() => _ReceiptViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReceiptViewState extends State<ReceiptView> {
|
||||||
|
final DialogService _dialogService = locator<DialogService>();
|
||||||
|
PrinterBluetoothManager printerManager = PrinterBluetoothManager();
|
||||||
|
bool printerLocked = false;
|
||||||
|
|
||||||
|
void print() async {
|
||||||
|
setState(() {
|
||||||
|
printerLocked = true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
PrinterSetting printerSetting = Redux.store!.state.settingState!.printer!;
|
||||||
|
printerManager.selectPrinter(
|
||||||
|
PrinterBluetooth(
|
||||||
|
printerDeviceToBluetoothDevice(printerSetting.device!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final int chunkSizeBytes = getChunkSize();
|
||||||
|
final int queueSleepTimeMs = getQueueSleep();
|
||||||
|
|
||||||
|
List<int> data = List.empty();
|
||||||
|
if (PrinterConst.encodingBigEncoding == printerSetting.encoding) {
|
||||||
|
data = await getReceiptImg(
|
||||||
|
printerSetting.paperSize!,
|
||||||
|
base64Decode(widget.transactionData.sellResponse!.checkPng!),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
data = await getReceipt(
|
||||||
|
printerSetting.encoding!,
|
||||||
|
printerSetting.paperSize!,
|
||||||
|
widget.transactionData.sellResponse!.check!
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final PosPrintResult printResult = await printerManager.writeBytes(
|
||||||
|
data,
|
||||||
|
chunkSizeBytes: chunkSizeBytes,
|
||||||
|
queueSleepTimeMs: queueSleepTimeMs,
|
||||||
|
);
|
||||||
|
if (printResult.value != 1) {
|
||||||
|
_dialogService.showDialog(description: printResult.msg);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await Future.delayed(const Duration(seconds: 7));
|
||||||
|
setState(() {
|
||||||
|
printerLocked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: whiteColor,
|
backgroundColor: whiteColor,
|
||||||
appBar: const ProductsAppBar(
|
appBar: ProductsAppBar(
|
||||||
title: 'Просмотр чека',
|
title: 'Просмотр чека',
|
||||||
|
actions: [
|
||||||
|
StoreConnector<AppState, PrinterSetting>(
|
||||||
|
converter: (store) => store.state.settingState!.printer!,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
final bool success =
|
||||||
|
snapshot.device != null && printerLocked == false;
|
||||||
|
return IconButton(
|
||||||
|
onPressed: success ? print : null,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.print,
|
||||||
|
color: success ? textColor : placeholderColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
child: Center(child: imageFromBase64String(transactionData.sellResponse)),
|
child: Center(
|
||||||
|
child:
|
||||||
|
imageFromBase64String(widget.transactionData.sellResponse),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
));
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () {
|
||||||
|
// Add your onPressed code here!
|
||||||
|
},
|
||||||
|
backgroundColor: successColor,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.share_rounded,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:satu/widgets/bar/products_app_bar.dart';
|
||||||
|
|
||||||
|
class ShareView extends StatelessWidget {
|
||||||
|
const ShareView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Scaffold(
|
||||||
|
appBar: ProductsAppBar(
|
||||||
|
title: 'Поделится',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue