first commit

This commit is contained in:
2026-02-07 15:57:09 +07:00
commit 157096f164
1153 changed files with 415766 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
import 'package:barcode/barcode.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:intl/intl.dart';
class StickerData {
final String businessName;
final String name;
final num price;
final String code;
final String mfg;
final bool isTwoIch;
final bool showBusinessName;
final bool showName;
final bool showPrice;
final bool showCode;
final bool showMfg;
final double nameFontSize;
final double priceFontSize;
final double mfgFontSize;
final double codeFontSize;
StickerData({
required this.businessName,
required this.name,
required this.price,
required this.code,
required this.mfg,
required this.isTwoIch,
required this.showBusinessName,
required this.showName,
required this.showPrice,
required this.showCode,
required this.showMfg,
required this.nameFontSize,
required this.priceFontSize,
required this.mfgFontSize,
required this.codeFontSize,
});
}
class StickerWidget extends StatelessWidget {
final StickerData data;
const StickerWidget({super.key, required this.data});
@override
Widget build(BuildContext context) {
final barcode = Barcode.code128();
final svg = barcode.toSvg(data.code, width: data.isTwoIch ? 300 : 200, height: 40, drawText: false);
String formatDateString(String? dateString) {
if (dateString == null) return 'N/A';
try {
final parsed = DateTime.parse(dateString);
return DateFormat('yyyy-MM-dd').format(parsed);
} catch (e) {
return 'N/A';
}
}
return Container(
width: data.isTwoIch ? 350 : 280,
height: 180,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (data.showBusinessName)
Text(
data.businessName,
style: TextStyle(fontSize: data.nameFontSize, color: Colors.black),
),
if (data.showName)
Text(
data.name,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: data.nameFontSize, color: Colors.black),
),
if (data.showPrice) const SizedBox(height: 2),
if (data.showPrice)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Price: ', style: TextStyle(fontSize: data.priceFontSize, color: Colors.black)),
Text(
NumberFormat.currency(symbol: '').format(data.price),
style: TextStyle(fontSize: data.priceFontSize, fontWeight: FontWeight.bold, color: Colors.black),
),
],
),
const SizedBox(height: 2),
if (data.showMfg)
Text(
'Packing Date: ${formatDateString(data.mfg)}',
style: TextStyle(fontSize: data.mfgFontSize, color: Colors.black),
),
const SizedBox(height: 4),
SizedBox(
height: 40,
width: double.infinity,
child: SvgPicture.string(
svg,
fit: BoxFit.contain,
),
),
const SizedBox(height: 2),
if (data.showCode) Text(data.code, style: TextStyle(fontSize: data.codeFontSize, color: Colors.black)),
],
),
);
}
}

View File

@@ -0,0 +1,29 @@
import 'dart:typed_data';
import 'package:bluetooth_print_plus/bluetooth_print_plus.dart';
Future<void> printLabelTest({
required String productName,
required String price,
required String date,
required String barcodeData,
required Uint8List pngBytes,
required bool isTwoInch,
}) async {
TscCommand tscCommand = TscCommand();
await tscCommand.cleanCommand();
await tscCommand.size(width: isTwoInch ? 45 : 38, height: 25); // mm
await tscCommand.gap(2);
await tscCommand.cls();
await tscCommand.image(image: pngBytes, x: 0, y: 0);
await tscCommand.print(1);
final cmd = await tscCommand.getCommand();
BluetoothPrintPlus.write(cmd);
}
String centerText(String text, {int lineWidth = 24}) {
if (text.length >= lineWidth) return text;
int totalPadding = lineWidth - text.length;
int leftPadding = totalPadding ~/ 2; // only add left padding
return ' ' * leftPadding + text;
}

View File

@@ -0,0 +1,26 @@
import 'package:mobile_pos/model/sale_transaction_model.dart';
import '../../Screens/Due Calculation/Model/due_collection_model.dart';
import '../../Screens/Purchase/Model/purchase_transaction_model.dart';
import '../../model/business_info_model.dart';
class PrintSalesTransactionModel {
PrintSalesTransactionModel({required this.transitionModel, required this.personalInformationModel});
BusinessInformationModel personalInformationModel;
SalesTransactionModel? transitionModel;
}
class PrintPurchaseTransactionModel {
PrintPurchaseTransactionModel({required this.purchaseTransitionModel, required this.personalInformationModel});
BusinessInformationModel personalInformationModel;
PurchaseTransaction? purchaseTransitionModel;
}
class PrintDueTransactionModel {
PrintDueTransactionModel({required this.dueTransactionModel, required this.personalInformationModel});
DueCollection? dueTransactionModel;
BusinessInformationModel personalInformationModel;
}

View File

@@ -0,0 +1,28 @@
import 'package:http/http.dart' as http;
import 'package:image/image.dart' as img;
Future<img.Image?> getNetworkImage(
String? url, {
int width = 250,
int height = 250,
}) async {
if (url == null) return null;
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode != 200) return null;
final _image = img.decodeImage(response.bodyBytes);
if (_image == null) return null;
return _image;
return img.copyResize(
_image,
width: width,
height: height,
interpolation: img.Interpolation.average,
);
// final img.Image grayscaleImage = img.grayscale(resizedImage);
} catch (e) {
return null;
}
}

View File

@@ -0,0 +1,241 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image/image.dart' as img;
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../../constant.dart';
import '../model/print_transaction_model.dart';
final printerPurchaseProviderNotifier = ChangeNotifierProvider((ref) => PrinterPurchase());
class PrinterPurchase extends ChangeNotifier {
List<BluetoothInfo> availableBluetoothDevices = [];
Future<void> getBluetooth() async {
final List<BluetoothInfo> bluetooths = await PrintBluetoothThermal.pairedBluetooths;
availableBluetoothDevices = bluetooths;
notifyListeners();
}
Future<bool> setConnect(String mac) async {
bool status = false;
final bool result = await PrintBluetoothThermal.connect(macPrinterAddress: mac);
if (result == true) {
connected = true;
status = true;
}
notifyListeners();
return status;
}
Future<bool> printCustomTicket(
{required PrintPurchaseTransactionModel printTransactionModel,
required String data,
required String paperSize}) async {
bool isPrinted = false;
bool? isConnected = await PrintBluetoothThermal.connectionStatus;
if (isConnected == true) {
List<int> bytes = await customPrintTicket(
printTransactionModel: printTransactionModel,
data: data,
paperSize: paperSize,
);
await PrintBluetoothThermal.writeBytes(bytes);
isPrinted = true;
} else {
isPrinted = false;
}
notifyListeners();
return isPrinted;
}
Future<List<int>> customPrintTicket(
{required PrintPurchaseTransactionModel printTransactionModel,
required String data,
required String paperSize}) async {
List<int> bytes = [];
PaperSize? size;
if (paperSize == '2 inch 58mm') {
size = PaperSize.mm58;
} else {
size = PaperSize.mm80;
}
try {
CapabilityProfile profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm58, profile);
Future<void> addText(String text, {PosStyles? styles, int linesAfter = 0}) async {
if (_isAscii(text)) {
bytes += generator.text(
text,
linesAfter: linesAfter,
styles: const PosStyles(
align: PosAlign.center,
),
);
} else {
final imageBytes = await _textToImageBytes(
generator,
text,
styles: const PosStyles(
align: PosAlign.center,
),
);
bytes += imageBytes;
if (linesAfter > 0) {
bytes += generator.feed(linesAfter);
}
}
}
// Add company name
final companyNameText = printTransactionModel.personalInformationModel.data?.companyName ?? '';
bytes += generator.text(
companyNameText,
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1,
);
// Add address
final address = printTransactionModel.personalInformationModel.data?.address ?? '';
if (address.isNotEmpty) {
bytes += generator.text(
address,
styles: const PosStyles(align: PosAlign.center),
);
}
// Add phone number
final phoneNumber = printTransactionModel.personalInformationModel.data?.phoneNumber ?? '';
if (phoneNumber.isNotEmpty) {
bytes += generator.text(
'Tel: $phoneNumber',
styles: const PosStyles(align: PosAlign.center),
linesAfter: printTransactionModel.personalInformationModel.data?.vatNo?.trim().isNotEmpty == true ? 0 : 1,
);
}
// Add VAT information if available
final vatNumber = printTransactionModel.personalInformationModel.data?.vatNo;
if (vatNumber != null &&
vatNumber.trim().isNotEmpty &&
printTransactionModel.personalInformationModel.data?.meta?.showVat == 1) {
final vatName = printTransactionModel.personalInformationModel.data?.vatName;
final label = vatName != null ? '$vatName:' : 'Shop GST:';
bytes += generator.text(
'$label $vatNumber',
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1,
);
}
await addText(
data,
styles: const PosStyles(
align: PosAlign.center,
),
linesAfter: 1,
);
// Add footer
bytes += generator.text('Thank you!', styles: const PosStyles(align: PosAlign.center, bold: true));
bytes += generator.text(
'Note: Goods once sold will not be taken back or exchanged.',
styles: const PosStyles(align: PosAlign.center, bold: false),
linesAfter: 1,
);
bytes += generator.text(
'Developed By: $companyName',
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1,
);
bytes += generator.cut();
return bytes;
} catch (e) {
print('Error generating print ticket: $e');
rethrow;
}
}
}
bool _isAscii(String input) {
for (final c in input.runes) {
if (c > 127) return false;
}
return true;
}
Future<List<int>> _textToImageBytes(
Generator generator,
String text, {
PosStyles? styles,
}) async {
try {
const double fontSize = 26.0;
const double horizontalPadding = 10.0;
const double lineSpacing = 1.2;
const double printerWidthMm = 58.0;
const double printerDpi = 203.0;
final double printerWidthPx = (printerWidthMm * printerDpi / 25.4) - (horizontalPadding * 2);
const String fallbackFont = 'Arial Unicode MS';
final textStyle = TextStyle(
fontSize: fontSize,
fontWeight: styles?.bold == true ? FontWeight.bold : FontWeight.normal,
color: Colors.black,
fontFamily: fallbackFont,
height: lineSpacing,
);
final textPainter = TextPainter(
text: TextSpan(text: text, style: textStyle),
textDirection: TextDirection.ltr,
maxLines: 100,
ellipsis: '...',
);
textPainter.layout(maxWidth: printerWidthPx);
final double imageWidth = printerWidthPx + (horizontalPadding * 2);
final double imageHeight = textPainter.height + 20.0;
final recorder = ui.PictureRecorder();
final canvas = Canvas(
recorder,
Rect.fromLTWH(0, 0, imageWidth, imageHeight),
);
textPainter.paint(
canvas,
Offset(horizontalPadding, 10.0),
);
final picture = recorder.endRecording();
final uiImage = await picture.toImage(
imageWidth.toInt(),
imageHeight.toInt(),
);
final byteData = await uiImage.toByteData(format: ui.ImageByteFormat.png);
final pngBytes = byteData!.buffer.asUint8List();
final image = img.decodePng(pngBytes)!;
return generator.image(image);
} catch (e) {
print('Error in _textToImageBytes: $e');
rethrow;
}
}

View File

@@ -0,0 +1,117 @@
import 'dart:ui';
import 'package:bluetooth_print_plus/bluetooth_print_plus.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mobile_pos/generated/l10n.dart' as lang;
final labelPrinterProvider = ChangeNotifierProvider((ref) => ThermalPrinter());
class ThermalPrinter extends ChangeNotifier {
@override
void addListener(VoidCallback listener) async {
// TODO: implement addListener
super.addListener(listener);
await BluetoothPrintPlus.startScan(timeout: Duration(seconds: 10));
}
List<BluetoothDevice> availableBluetoothDevices = [];
bool isBluetoothConnected = false;
// Future<void> getBluetooth() async {
// availableBluetoothDevices = await BluetoothPrintPlus.scanResults;
// isBluetoothConnected = await PrintBluetoothThermal.connectionStatus;
// notifyListeners();
// }
//
// Future<bool> setConnect(String mac) async {
// bool status = false;
// final bool result = await PrintBluetoothThermal.connect(macPrinterAddress: mac);
// if (result == true) {
// isBluetoothConnected = true;
// status = true;
// }
// notifyListeners();
// return status;
// }
Future<dynamic> listOfBluDialog({required BuildContext context}) async {
// begin scan
// final _scanResultsSubscription = BluetoothPrintPlus.scanResults.listen((event) {
// print('${event.length}');
// // if (mounted) {
// // setState(() {
// // _scanResults = event;
// // });
// // }
// });
return showCupertinoDialog(
context: context,
builder: (_) {
return WillPopScope(
onWillPop: () async => false,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: CupertinoAlertDialog(
insetAnimationCurve: Curves.bounceInOut,
// content: Container(
// height: availableBluetoothDevices.isNotEmpty ? (availableBluetoothDevices.length * 80).toDouble() : 150,
// width: double.maxFinite,
// child: StreamBuilder(
// stream: FlutterBluetoothPrinter.discovery,
// builder: (context, snapshot){
//
//
// // final List<BluetoothDevice> hh = snapshot.data as List<BluetoothDevice>;
// print('this is it--------->$snapshot');
// return ListView.builder(
// itemCount: 0,
// itemBuilder: (context, index){
// // final device = hh.elementAt(index);
// return ListTile(
// // title: Text(device.name ?? 'No Name'),
// // subtitle: Text(device.address),
// onTap: (){
// // do anything
// // FlutterBluetoothPrinter.printImage(
// // address: device.address,
// // image: // some image
// // );
// }
// );
// }
// );
// }
// )),
title: Text(
'Connect Your Device',
textAlign: TextAlign.start,
),
actions: <Widget>[
CupertinoDialogAction(
child: Text(
lang.S.of(context).cancel,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.red),
),
onPressed: () async {
Future.delayed(const Duration(milliseconds: 100), () {
Navigator.pop(context);
});
},
),
],
),
),
);
},
);
}
// Future<void> printSalesThermalInvoiceNow({required PrintSalesTransactionModel transaction, required List<SalesDetails>? productList, required BuildContext context}) async {
// await getBluetooth();
// isBluetoothConnected ? SalesThermalPrinterInvoice().printSalesTicket(printTransactionModel: transaction, productList: productList) : listOfBluDialog(context: context);
// }
}

View File

@@ -0,0 +1,166 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mobile_pos/Screens/Products/Model/product_total_stock_model.dart';
import 'package:mobile_pos/generated/l10n.dart' as lang;
import 'package:mobile_pos/model/business_info_model.dart';
import 'package:nb_utils/nb_utils.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../../Screens/Products/Model/product_model.dart';
import '../../Screens/Purchase/Model/purchase_transaction_model.dart' hide Product;
import '../../constant.dart';
import '../../model/sale_transaction_model.dart';
import '../model/print_transaction_model.dart';
import '../thermal_invoice_due.dart';
import '../thermal_invoice_purchase.dart';
import '../thermal_invoice_sales.dart';
import '../thermal_invoice_stock.dart';
import '../thermal_lebels_printing.dart';
final thermalPrinterProvider = ChangeNotifierProvider((ref) => ThermalPrinter());
class ThermalPrinter extends ChangeNotifier {
List<BluetoothInfo> availableBluetoothDevices = [];
bool isBluetoothConnected = false;
Future<void> getBluetooth() async {
availableBluetoothDevices = await PrintBluetoothThermal.pairedBluetooths;
isBluetoothConnected = await PrintBluetoothThermal.connectionStatus;
notifyListeners();
}
Future<bool> setConnect(String mac) async {
bool status = false;
final bool result = await PrintBluetoothThermal.connect(macPrinterAddress: mac);
if (result == true) {
isBluetoothConnected = true;
status = true;
}
notifyListeners();
return status;
}
Future<dynamic> listOfBluDialog({required BuildContext context}) async {
return showCupertinoDialog(
context: context,
builder: (_) {
return WillPopScope(
onWillPop: () async => false,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: CupertinoAlertDialog(
insetAnimationCurve: Curves.bounceInOut,
content: Container(
height: availableBluetoothDevices.isNotEmpty ? (availableBluetoothDevices.length * 80).toDouble() : 150,
width: double.maxFinite,
child: availableBluetoothDevices.isNotEmpty
? ListView.builder(
padding: EdgeInsets.all(0), // Removed padding from ListView
shrinkWrap: true,
itemCount: availableBluetoothDevices.isNotEmpty ? availableBluetoothDevices.length : 0,
itemBuilder: (context1, index) {
return ListTile(
contentPadding: EdgeInsets.all(0), // Removed padding from ListTile
onTap: () async {
BluetoothInfo select = availableBluetoothDevices[index];
bool isConnect = await setConnect(select.macAdress);
isConnect ? finish(context1) : toast(lang.S.of(context1).tryAgain);
},
title: Text(
availableBluetoothDevices[index].name,
style: TextStyle(fontSize: 12, color: Colors.black, fontWeight: FontWeight.w500),
),
subtitle: Text(
lang.S.of(context1).clickToConnect,
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade500,
),
),
);
},
)
: const Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.bluetooth_disabled,
size: 40,
color: kMainColor,
),
SizedBox(
height: 4,
),
Text(
'Not available',
style: TextStyle(fontSize: 14, color: kGreyTextColor),
)
],
),
),
),
title: Text(
'Connect Your Device',
textAlign: TextAlign.start,
),
actions: <Widget>[
CupertinoDialogAction(
child: Text(
lang.S.of(context).cancel,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.red),
),
onPressed: () async {
Future.delayed(const Duration(milliseconds: 100), () {
Navigator.pop(context);
});
},
),
],
),
),
);
},
);
}
Future<void> printSalesThermalInvoiceNow({required PrintSalesTransactionModel transaction, required List<SalesDetails>? productList, required BuildContext context}) async {
await getBluetooth();
isBluetoothConnected
? SalesThermalPrinterInvoice().printSalesTicket(printTransactionModel: transaction, productList: productList, context: context)
: listOfBluDialog(context: context);
}
Future<void> printPurchaseThermalInvoiceNow(
{required PrintPurchaseTransactionModel transaction, required List<PurchaseDetails>? productList, required BuildContext context, required String? invoiceSize}) async {
await getBluetooth();
isBluetoothConnected
? PurchaseThermalPrinterInvoice().printPurchaseThermalInvoice(printTransactionModel: transaction, productList: productList, context: context)
: listOfBluDialog(context: context);
}
Future<void> printDueThermalInvoiceNow({required PrintDueTransactionModel transaction, required String? invoiceSize, required BuildContext context}) async {
await getBluetooth();
isBluetoothConnected
? DueThermalPrinterInvoice().printDueTicket(printDueTransactionModel: transaction, invoiceSize: invoiceSize, context: context)
: listOfBluDialog(context: context);
}
Future<void> printStockInvoiceNow(
{required List<Product> products, required BusinessInformationModel businessInformationModel, required BuildContext context, required ProductListResponse totalStock}) async {
await getBluetooth();
isBluetoothConnected
? StockThermalPrinterInvoice().printStockTicket(businessInformationModel: businessInformationModel, productList: products, stock: totalStock)
: listOfBluDialog(context: context);
}
Future<void> printLabelsNow({required List<Product> products, required BuildContext context}) async {
await getBluetooth();
isBluetoothConnected ? SalesThermalLabels().printLabels(productList: products) : listOfBluDialog(context: context);
}
}

View File

@@ -0,0 +1,57 @@
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
Future<Uint8List?> createImageFromWidget(BuildContext context, Widget widget, {Duration? wait, Size? logicalSize, Size? imageSize}) async {
final repaintBoundary = RenderRepaintBoundary();
logicalSize ??= View.of(context).physicalSize / View.of(context).devicePixelRatio;
imageSize ??= View.of(context).physicalSize;
assert(logicalSize.aspectRatio == imageSize.aspectRatio, 'logicalSize and imageSize must not be the same');
final renderView = RenderView(
child: RenderPositionedBox(alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
physicalConstraints: BoxConstraints.tight(logicalSize),
logicalConstraints: BoxConstraints.tight(logicalSize),
devicePixelRatio: 1,
),
view: View.of(context) //PlatformDispatcher.instance.views.first,
);
final pipelineOwner = PipelineOwner();
final buildOwner = BuildOwner(focusManager: FocusManager());
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: Directionality(
textDirection: TextDirection.ltr,
child: widget,
)).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
if (wait != null) {
await Future.delayed(wait);
}
buildOwner
..buildScope(rootElement)
..finalizeTree();
pipelineOwner
..flushLayout()
..flushCompositingBits()
..flushPaint();
final image = await repaintBoundary.toImage(pixelRatio: imageSize.width / logicalSize.width);
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}

View File

@@ -0,0 +1,510 @@
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'package:intl/intl.dart';
import 'package:mobile_pos/Const/lalnguage_data.dart';
import 'package:mobile_pos/service/thermal_print/src/templates/_due_collection_invoice_template.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../Const/api_config.dart';
import '../constant.dart';
import 'model/print_transaction_model.dart';
import 'network_image.dart';
class DueThermalPrinterInvoice {
///_________Due________________________
Future<void> printDueTicket(
{required PrintDueTransactionModel printDueTransactionModel,
required String? invoiceSize,
required BuildContext context}) async {
bool? isConnected = await PrintBluetoothThermal.connectionStatus;
if (isConnected == true) {
bool defould = (printDueTransactionModel.personalInformationModel.data?.invoiceLanguage == 'english' ||
printDueTransactionModel.personalInformationModel.data?.invoiceLanguage == null)
? true
: false;
List<int> bytes = [];
final is80mm = printDueTransactionModel.personalInformationModel.data?.invoiceSize == '3_inch_80mm' &&
printDueTransactionModel.personalInformationModel.data?.invoiceSize != null;
if (defould) {
bytes = (is80mm)
? await getDueTicket80mm(printDueTransactionModel: printDueTransactionModel)
: await getDueTicket50mm(printDueTransactionModel: printDueTransactionModel);
} else {
final bool isRTL = rtlLang.contains(await getLanguageName());
DueThermalInvoiceTemplate dueThermalInvoiceTemplate = DueThermalInvoiceTemplate(
context: context, printDueTransactionModel: printDueTransactionModel, is58mm: !is80mm, isRTL: isRTL);
bytes = await dueThermalInvoiceTemplate.template;
}
await PrintBluetoothThermal.writeBytes(bytes);
} else {}
}
Future<List<int>> getDueTicket50mm({required PrintDueTransactionModel printDueTransactionModel}) async {
final transactions = printDueTransactionModel.dueTransactionModel!.transactions ?? [];
List<String> paymentLabels = [];
for (var item in transactions) {
String label;
switch (item.transactionType) {
case 'cash_payment':
label = 'Cash';
break;
case 'cheque_payment':
label = 'Cheque';
break;
case 'wallet_payment':
label = 'Wallet';
break;
default:
label = item.paymentType?.name ?? 'n/a';
}
paymentLabels.add(label);
}
final paidViaText = "Paid Via : ${paymentLabels.join(', ')}";
List<int> bytes = [];
CapabilityProfile profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm58, profile);
// final ByteData data = await rootBundle.load('images/logo.png');
// final Uint8List imageBytes = data.buffer.asUint8List();
// final Image? imagez = decodeImage(imageBytes);
// bytes += generator.image(imagez!);
final _qrlogo = await getNetworkImage(
"${APIConfig.domain}${printDueTransactionModel.personalInformationModel.data?.invoiceScannerLogo}");
final _logo = await getNetworkImage(
"${APIConfig.domain}${printDueTransactionModel.personalInformationModel.data?.thermalInvoiceLogo}");
///____________Image__________________________________
if (_logo != null && printDueTransactionModel.personalInformationModel.data?.showThermalInvoiceLogo == 1) {
final img.Image resized = img.copyResize(
_logo,
width: 184,
);
final img.Image grayscale = img.grayscale(resized);
bytes += generator.imageRaster(grayscale, imageFn: PosImageFn.bitImageRaster);
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showCompanyName == 1) {
bytes += generator.text(printDueTransactionModel.personalInformationModel.data?.companyName ?? '',
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1);
}
if (printDueTransactionModel.dueTransactionModel?.branch?.name != null) {
bytes += generator.text(printDueTransactionModel.dueTransactionModel?.branch?.name ?? '',
styles: const PosStyles(align: PosAlign.center));
}
bytes += generator.text(
'Seller :${printDueTransactionModel.dueTransactionModel?.user?.role == "shop-owner" ? 'Admin' : printDueTransactionModel.dueTransactionModel?.user?.name ?? ''}',
styles: const PosStyles(align: PosAlign.center));
if (printDueTransactionModel.personalInformationModel.data?.meta?.showAddress == 1) {
if (printDueTransactionModel.dueTransactionModel?.branch?.address != null ||
printDueTransactionModel.personalInformationModel.data?.address != null) {
bytes += generator.text(
printDueTransactionModel.dueTransactionModel?.branch?.address ??
printDueTransactionModel.personalInformationModel.data?.address ??
'',
styles: const PosStyles(align: PosAlign.center),
);
}
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showVat == 1) {
if (printDueTransactionModel.personalInformationModel.data?.vatNo != null &&
printDueTransactionModel.personalInformationModel.data?.meta?.showVat == 1) {
bytes += generator.text(
"${printDueTransactionModel.personalInformationModel.data?.vatName ?? 'VAT No :'}${printDueTransactionModel.personalInformationModel.data?.vatNo ?? ''}",
styles: const PosStyles(align: PosAlign.center));
}
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showPhoneNumber == 1) {
if (printDueTransactionModel.dueTransactionModel?.branch?.phone != null ||
printDueTransactionModel.personalInformationModel.data?.phoneNumber != null) {
bytes += generator.text(
printDueTransactionModel.dueTransactionModel?.branch?.phone ??
printDueTransactionModel.personalInformationModel.data?.phoneNumber ??
'n/a',
styles: const PosStyles(align: PosAlign.center));
}
}
bytes += generator.emptyLines(1);
bytes += generator.text('Receipt',
styles: const PosStyles(
underline: true,
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1);
bytes += generator.text('Received From: ${printDueTransactionModel.dueTransactionModel?.party?.name} ',
styles: const PosStyles(align: PosAlign.left));
bytes += generator.text('Mobile: ${printDueTransactionModel.dueTransactionModel?.party?.phone}',
styles: const PosStyles(align: PosAlign.left));
// bytes += generator.text('Received By: ${printDueTransactionModel.dueTransactionModel?.user?.name}', styles: const PosStyles(align: PosAlign.left));
bytes += generator.text('Receipt: ${printDueTransactionModel.dueTransactionModel?.invoiceNumber ?? 'Not Provided'}',
styles: const PosStyles(align: PosAlign.left));
if (printDueTransactionModel.dueTransactionModel?.paymentDate != null) {
DateTime saleDate = DateTime.parse(printDueTransactionModel.dueTransactionModel!.paymentDate!);
String formattedDate = DateFormat('M/d/yyyy h:mm a').format(saleDate);
bytes += generator.text(
'Date: $formattedDate',
styles: const PosStyles(align: PosAlign.left),
linesAfter: 1,
);
}
// bytes += generator.hr();
// bytes += generator.row([
// PosColumn(text: 'Invoice', width: 8, styles: const PosStyles(align: PosAlign.left, bold: true)),
// PosColumn(text: 'Due', width: 4, styles: const PosStyles(align: PosAlign.right, bold: true)),
// ]);
// bytes += generator.hr();
bytes += generator.row([
PosColumn(
text: 'Total Due',
width: 8,
styles: const PosStyles(
align: PosAlign.left,
)),
PosColumn(
text: printDueTransactionModel.dueTransactionModel!.totalDue.toString(),
width: 4,
styles: const PosStyles(
align: PosAlign.right,
)),
]);
bytes += generator.hr();
bytes += generator.row([
PosColumn(
text: 'Payment Amount:',
width: 8,
styles: const PosStyles(
align: PosAlign.left,
)),
PosColumn(
text: printDueTransactionModel.dueTransactionModel!.payDueAmount.toString(),
width: 4,
styles: const PosStyles(
align: PosAlign.right,
)),
]);
bytes += generator.row([
PosColumn(text: 'Remaining Due:', width: 8, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(
text: printDueTransactionModel.dueTransactionModel!.dueAmountAfterPay.toString(),
width: 4,
styles: const PosStyles(align: PosAlign.right, bold: true)),
]);
bytes += generator.hr();
// bytes += generator.row([
// PosColumn(
// text: 'Payment Type:',
// width: 8,
// styles: const PosStyles(
// align: PosAlign.left,
// )),
// PosColumn(
// text: printDueTransactionModel.dueTransactionModel!.paymentType?.name ?? 'N/A',
// width: 4,
// styles: const PosStyles(
// align: PosAlign.right,
// )),
// ]);
bytes += generator.text(
paidViaText,
styles: const PosStyles(
align: PosAlign.left,
),
linesAfter: 1,
);
// ticket.feed(2);
if (printDueTransactionModel.personalInformationModel.data?.gratitudeMessage != null &&
printDueTransactionModel.personalInformationModel.data?.showGratitudeMsg == 1) {
bytes += generator.text(printDueTransactionModel.personalInformationModel.data?.gratitudeMessage ?? '',
styles: const PosStyles(align: PosAlign.center, bold: true));
bytes += generator.text(printDueTransactionModel.dueTransactionModel!.paymentDate ?? '',
styles: const PosStyles(align: PosAlign.center), linesAfter: 1);
}
if ((printDueTransactionModel.personalInformationModel.data?.invoiceNoteLevel != null ||
printDueTransactionModel.personalInformationModel.data?.invoiceNote != null) &&
printDueTransactionModel.personalInformationModel.data?.showNote == 1) {
bytes += generator.text(
'${printDueTransactionModel.personalInformationModel.data?.invoiceNoteLevel ?? ''}: ${printDueTransactionModel.personalInformationModel.data?.invoiceNote ?? ''}',
styles: const PosStyles(align: PosAlign.left, bold: false),
linesAfter: 1,
);
}
if (printDueTransactionModel.personalInformationModel.data?.showInvoiceScannerLogo == 1) {
if (_qrlogo != null) {
final img.Image resized = img.copyResize(
_qrlogo,
width: 120,
height: 120,
);
final img.Image grayscale = img.grayscale(resized);
bytes += generator.imageRaster(grayscale, imageFn: PosImageFn.bitImageRaster);
}
}
if (printDueTransactionModel.personalInformationModel.data?.developByLevel != null ||
printDueTransactionModel.personalInformationModel.data?.developBy != null) {
bytes += generator.text(
'${printDueTransactionModel.personalInformationModel.data?.developByLevel ?? ''}: ${printDueTransactionModel.personalInformationModel.data?.developBy ?? ''}',
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1);
}
bytes += generator.cut();
return bytes;
}
Future<List<int>> getDueTicket80mm({required PrintDueTransactionModel printDueTransactionModel}) async {
final transactions = printDueTransactionModel.dueTransactionModel!.transactions ?? [];
List<String> paymentLabels = [];
for (var item in transactions) {
String label;
switch (item.transactionType) {
case 'cash_payment':
label = 'Cash';
break;
case 'cheque_payment':
label = 'Cheque';
break;
case 'wallet_payment':
label = 'Wallet';
break;
default:
label = item.paymentType?.name ?? 'n/a';
}
paymentLabels.add(label);
}
final paidViaText = "Paid Via : ${paymentLabels.join(', ')}";
List<int> bytes = [];
final _qrlogo = await getNetworkImage(
"${APIConfig.domain}${printDueTransactionModel.personalInformationModel.data?.invoiceScannerLogo}");
final _logo = await getNetworkImage(
"${APIConfig.domain}${printDueTransactionModel.personalInformationModel.data?.thermalInvoiceLogo}");
CapabilityProfile profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm80, profile);
///____________Image__________________________________
if (_logo != null) {
final img.Image resized = img.copyResize(
_logo,
width: 184,
);
final img.Image grayscale = img.grayscale(resized);
bytes += generator.imageRaster(grayscale, imageFn: PosImageFn.bitImageRaster);
}
///____________Header_____________________________________
if (printDueTransactionModel.personalInformationModel.data?.meta?.showCompanyName == 1) {
bytes += generator.text(printDueTransactionModel.personalInformationModel.data?.companyName ?? '',
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1);
}
if (printDueTransactionModel.dueTransactionModel?.branch?.name != null) {
bytes += generator.text('Branch: ${printDueTransactionModel.dueTransactionModel?.branch?.name}',
styles: const PosStyles(align: PosAlign.center));
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showAddress == 1) {
if (printDueTransactionModel.dueTransactionModel?.branch?.address != null ||
printDueTransactionModel.personalInformationModel.data?.address != null) {
bytes += generator.text(
'Address: ${printDueTransactionModel.dueTransactionModel?.branch?.address ?? printDueTransactionModel.personalInformationModel.data?.address ?? ''}',
styles: const PosStyles(align: PosAlign.center));
}
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showPhoneNumber == 1) {
if (printDueTransactionModel.dueTransactionModel?.branch?.phone != null ||
printDueTransactionModel.personalInformationModel.data?.phoneNumber != null) {
bytes += generator.text(
'Mobile: ${printDueTransactionModel.dueTransactionModel?.branch?.phone ?? printDueTransactionModel.personalInformationModel.data?.phoneNumber ?? ''}',
styles: const PosStyles(align: PosAlign.center));
}
}
if (printDueTransactionModel.personalInformationModel.data?.meta?.showVat == 1) {
if (printDueTransactionModel.personalInformationModel.data?.vatNo != null &&
printDueTransactionModel.personalInformationModel.data?.meta?.showVat == 1) {
bytes += generator.text(
"${printDueTransactionModel.personalInformationModel.data?.vatName ?? 'VAT No'}: ${printDueTransactionModel.personalInformationModel.data?.vatNo}",
styles: const PosStyles(align: PosAlign.center));
}
}
bytes += generator.emptyLines(1);
bytes += generator.text('Receipt',
styles: const PosStyles(
bold: true,
underline: true,
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1);
///__________Customer_and_time_section_______________________
bytes += generator.row([
PosColumn(
text: 'Receipt: ${printDueTransactionModel.dueTransactionModel?.invoiceNumber ?? 'Not Provided'}',
width: 6,
styles: const PosStyles(align: PosAlign.left)),
PosColumn(
text:
'Date: ${DateFormat.yMd().format(DateTime.parse(printDueTransactionModel.dueTransactionModel?.paymentDate ?? DateTime.now().toString()))}',
width: 6,
styles: const PosStyles(align: PosAlign.right)),
]);
bytes += generator.row([
PosColumn(
text: 'Name: ${printDueTransactionModel.dueTransactionModel?.party?.name ?? ''}',
width: 6,
styles: const PosStyles(align: PosAlign.left)),
PosColumn(
text:
'Time: ${DateFormat.jm().format(DateTime.parse(printDueTransactionModel.dueTransactionModel?.paymentDate ?? DateTime.now().toString()))}',
width: 6,
styles: const PosStyles(align: PosAlign.right)),
]);
bytes += generator.row([
PosColumn(
text: 'Mobile: ${printDueTransactionModel.dueTransactionModel?.party?.phone ?? ''}',
width: 6,
styles: const PosStyles(align: PosAlign.left)),
PosColumn(
text:
'Received By: ${printDueTransactionModel.dueTransactionModel?.user?.role == "shop-owner" ? 'Admin' : printDueTransactionModel.dueTransactionModel!.user?.name}',
width: 6,
styles: const PosStyles(align: PosAlign.right)),
]);
bytes += generator.emptyLines(1);
bytes += generator.hr();
bytes += generator.row([
PosColumn(text: 'SL', width: 1, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(text: 'Invoice', width: 6, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(text: 'Due', width: 5, styles: const PosStyles(align: PosAlign.right, bold: true)),
]);
bytes += generator.hr();
bytes += generator.row([
PosColumn(text: '1', width: 1, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(
text: printDueTransactionModel.dueTransactionModel?.invoiceNumber ?? '',
width: 6,
styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(
text: formatPointNumber(printDueTransactionModel.dueTransactionModel?.totalDue ?? 0, addComma: true),
width: 5,
styles: const PosStyles(align: PosAlign.right)),
]);
bytes += generator.hr();
bytes += generator.row([
PosColumn(
text: 'Payment Amount:',
width: 9,
styles: const PosStyles(
align: PosAlign.right,
)),
PosColumn(
text: formatPointNumber(printDueTransactionModel.dueTransactionModel?.payDueAmount ?? 0, addComma: true),
width: 3,
styles: const PosStyles(
align: PosAlign.right,
)),
]);
bytes += generator.row([
PosColumn(
text: 'Remaining Due:',
width: 9,
styles: const PosStyles(
align: PosAlign.right,
)),
PosColumn(
text:
formatPointNumber((printDueTransactionModel.dueTransactionModel?.dueAmountAfterPay ?? 0), addComma: true),
width: 3,
styles: const PosStyles(
align: PosAlign.right,
)),
]);
// bytes += generator.hr();
bytes += generator.text(
'-----------------------------',
styles: const PosStyles(align: PosAlign.right),
);
bytes += generator.text(
paidViaText,
styles: const PosStyles(
align: PosAlign.left,
),
linesAfter: 1,
);
if (printDueTransactionModel.personalInformationModel.data?.gratitudeMessage != null &&
printDueTransactionModel.personalInformationModel.data?.showGratitudeMsg == 1) {
bytes += generator.text(printDueTransactionModel.personalInformationModel.data?.gratitudeMessage ?? '',
styles: const PosStyles(align: PosAlign.center, bold: true));
}
bytes += generator.text(printDueTransactionModel.dueTransactionModel!.paymentDate ?? '',
styles: const PosStyles(align: PosAlign.center), linesAfter: 1);
if ((printDueTransactionModel.personalInformationModel.data?.invoiceNoteLevel != null ||
printDueTransactionModel.personalInformationModel.data?.invoiceNote != null) &&
printDueTransactionModel.personalInformationModel.data?.showNote == 1) {
bytes += generator.text(
'${printDueTransactionModel.personalInformationModel.data?.invoiceNoteLevel ?? ''}: ${printDueTransactionModel.personalInformationModel.data?.invoiceNote ?? ''}',
styles: const PosStyles(align: PosAlign.left, bold: false),
linesAfter: 1,
);
}
if (printDueTransactionModel.personalInformationModel.data?.showInvoiceScannerLogo == 1) {
if (_qrlogo != null) {
final img.Image resized = img.copyResize(
_qrlogo,
width: 120,
height: 120,
);
final img.Image grayscale = img.grayscale(resized);
bytes += generator.imageRaster(grayscale, imageFn: PosImageFn.bitImageRaster);
}
}
if (printDueTransactionModel.personalInformationModel.data?.developByLevel != null ||
printDueTransactionModel.personalInformationModel.data?.developBy != null) {
bytes += generator.text(
'${printDueTransactionModel.personalInformationModel.data?.developByLevel ?? ''}: ${printDueTransactionModel.personalInformationModel.data?.developBy ?? ''}',
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1);
}
bytes += generator.cut();
return bytes;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,195 @@
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:image/image.dart' as img;
import 'package:intl/intl.dart';
import 'package:mobile_pos/Screens/Products/Model/product_model.dart';
import 'package:nb_utils/nb_utils.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../Const/api_config.dart';
import '../Screens/Products/Model/product_total_stock_model.dart';
import '../constant.dart';
import '../model/business_info_model.dart';
import 'network_image.dart';
class StockThermalPrinterInvoice {
///________Sales____________________
Future<void> printStockTicket({
required BusinessInformationModel businessInformationModel,
required List<Product>? productList,
required ProductListResponse stock,
}) async {
bool? isConnected = await PrintBluetoothThermal.connectionStatus;
if (isConnected == true) {
String st = await PrintBluetoothThermal.platformVersion;
List<int> bytes = await getStockTicket(
businessInformationModel: businessInformationModel,
productList: productList,
is80mm: businessInformationModel.data?.invoiceSize == '3_inch_80mm',
stockValue: stock);
if (productList?.isNotEmpty ?? false) {
await PrintBluetoothThermal.writeBytes(bytes);
EasyLoading.showSuccess('Successfully Printed');
} else {
toast('No Product Found');
}
} else {
EasyLoading.showError('Unable to connect with printer');
}
}
Future<List<int>> getStockTicket(
{required BusinessInformationModel businessInformationModel,
required List<Product>? productList,
required bool is80mm,
ProductListResponse? stockValue}) async {
final _logo = await getNetworkImage("${APIConfig.domain}${businessInformationModel.data?.thermalInvoiceLogo}");
String formattedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
String formattedTime = DateFormat('hh:mm a').format(DateTime.now());
List<int> bytes = [];
CapabilityProfile profile = await CapabilityProfile.load();
final generator = Generator(is80mm ? PaperSize.mm80 : PaperSize.mm58, profile);
///____________Image__________________________________
if (_logo != null && businessInformationModel.data?.showThermalInvoiceLogo == 1) {
final img.Image resized = img.copyResize(
_logo,
width: 184,
);
final img.Image grayscale = img.grayscale(resized);
bytes += generator.imageRaster(grayscale, imageFn: PosImageFn.bitImageRaster);
}
if (businessInformationModel.data?.meta?.showCompanyName == 1) {
bytes += generator.text(
businessInformationModel.data?.companyName ?? '',
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1,
);
}
bytes += generator.text(
'Seller :${businessInformationModel.data?.user?.role == "shop-owner" ? 'Admin' : businessInformationModel.data?.user?.name}',
styles: const PosStyles(align: PosAlign.center));
if (businessInformationModel.data?.address != null) {
bytes +=
generator.text(businessInformationModel.data?.address ?? '', styles: const PosStyles(align: PosAlign.center));
}
if (businessInformationModel.data?.meta?.showPhoneNumber == 1) {
if (businessInformationModel.data?.phoneNumber != null) {
bytes += generator.text('Phone : ${businessInformationModel.data?.phoneNumber ?? ''}',
styles: const PosStyles(align: PosAlign.center));
}
}
if (businessInformationModel.data?.meta?.showVat == 1) {
if (businessInformationModel.data?.vatNo != null && businessInformationModel.data?.meta?.showVat == 1) {
bytes += generator.text(
"${businessInformationModel.data?.vatName ?? 'VAT No'}: ${businessInformationModel.data?.vatNo ?? ''}",
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1);
}
}
bytes += generator.text('Stock List',
styles: const PosStyles(
align: PosAlign.center,
underline: true,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1);
bytes += generator.text('Date : $formattedDate', styles: const PosStyles(align: PosAlign.left));
bytes += generator.text('Time : $formattedTime', styles: const PosStyles(align: PosAlign.left));
bytes += generator.hr();
bytes += generator.row([
PosColumn(text: 'SL', width: 1, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(text: 'Item Name', width: is80mm ? 7 : 6, styles: const PosStyles(align: PosAlign.left, bold: true)),
PosColumn(text: 'Qty', width: 2, styles: const PosStyles(align: PosAlign.center, bold: true)),
PosColumn(text: 'Price', width: is80mm ? 2 : 3, styles: const PosStyles(align: PosAlign.right, bold: true)),
]);
bytes += generator.hr();
List.generate(productList?.length ?? 1, (index) {
final stokePrice = productList![index].stocks != null && productList[index].stocks!.isNotEmpty
? productList[index].stocks!.last.productPurchasePrice
: 0;
return bytes += generator.row([
PosColumn(
text: '${index + 1}',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
)),
PosColumn(
text: '${productList[index].productName}',
width: is80mm ? 7 : 6,
styles: const PosStyles(
align: PosAlign.left,
)),
PosColumn(
text: '${productList[index].stocksSumProductStock}',
width: 2,
styles: const PosStyles(align: PosAlign.center)),
PosColumn(
text: (formatPointNumber(stokePrice ?? 0, addComma: true)),
width: is80mm ? 2 : 3,
styles: const PosStyles(align: PosAlign.right)),
]);
});
bytes += generator.hr();
bytes += generator.row([
PosColumn(
text: 'Total Stock value :',
width: 9,
styles: const PosStyles(
align: PosAlign.right,
)),
PosColumn(
text: formatPointNumber(stockValue!.totalStockValue),
width: 3,
styles: const PosStyles(
align: PosAlign.right,
)),
]);
bytes += generator.text('');
// bytes += generator.text('Developed By: $companyName', styles: const PosStyles(align: PosAlign.center), linesAfter: 1);
if (businessInformationModel.data?.gratitudeMessage != null &&
businessInformationModel.data?.showGratitudeMsg == 1) {
bytes += generator.text(
businessInformationModel.data?.gratitudeMessage ?? '',
styles: const PosStyles(align: PosAlign.center, bold: true),
linesAfter: 1,
);
}
if ((businessInformationModel.data?.invoiceNoteLevel != null ||
businessInformationModel.data?.invoiceNote != null) &&
businessInformationModel.data?.showNote == 1) {
bytes += generator.text(
'${businessInformationModel.data?.invoiceNoteLevel ?? ''}: ${businessInformationModel.data?.invoiceNote ?? ''}',
styles: const PosStyles(align: PosAlign.left, bold: false),
linesAfter: 1,
);
}
if (businessInformationModel.data?.developByLink != null) {
bytes += generator.qrcode(
businessInformationModel.data?.developByLink ?? '',
);
bytes += generator.emptyLines(1);
}
if (businessInformationModel.data?.developByLevel != null || businessInformationModel.data?.developBy != null) {
bytes += generator.text(
'${businessInformationModel.data?.developByLevel ?? ''}: ${businessInformationModel.data?.developBy ?? ''}',
styles: const PosStyles(align: PosAlign.center),
linesAfter: 1);
}
bytes += generator.cut();
return bytes;
}
}

View File

@@ -0,0 +1,47 @@
import 'package:bluetooth_print_plus/bluetooth_print_plus.dart';
import 'package:mobile_pos/Screens/Products/Model/product_model.dart';
class SalesThermalLabels {
///________Sales____________________
Future<void> printLabels({required List<Product>? productList}) async {
bool conn = BluetoothPrintPlus.isConnected;
print('Collection State----------------> $conn');
///_________________Old_______________________________________________
// bool? isConnected = await PrintBluetoothThermal.connectionStatus;
// if (isConnected == true) {
// List<int> bytes = await labelPrinter(productList: productList);
// if (true) {
// await PrintBluetoothThermal.writeBytes(bytes);
// EasyLoading.showSuccess('Successfully Printed');
// } else {
// toast('No Product Found');
// }
// } else {
// EasyLoading.showError('Unable to connect with printer');
// }
}
//
// Future<List<int>> labelPrinter({required List<ProductModel>? productList}) async {
// List<int> bytes = [];
// CapabilityProfile profile = await CapabilityProfile.load();
//
// final generator = Generator(PaperSize.mm80, profile);
//
// ///____________Header_____________________________________
// bytes += generator.text('This is a test',
// styles: const PosStyles(
// align: PosAlign.center,
// height: PosTextSize.size2,
// width: PosTextSize.size2,
// ),
// linesAfter: 1);
// final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
// bytes += generator.barcode(Barcode.upcA(barData));
//
// bytes += generator.cut();
// return bytes;
// }
}