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 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 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> getDueTicket50mm({required PrintDueTransactionModel printDueTransactionModel}) async { final transactions = printDueTransactionModel.dueTransactionModel!.transactions ?? []; List 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 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> getDueTicket80mm({required PrintDueTransactionModel printDueTransactionModel}) async { final transactions = printDueTransactionModel.dueTransactionModel!.transactions ?? []; List 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 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; } }