From 3624f75bea8bf1044996be646e134a7d1bc83c3b Mon Sep 17 00:00:00 2001 From: efrilm Date: Mon, 1 Sep 2025 22:36:26 +0700 Subject: [PATCH] feat: print void --- lib/core/function/app_function.dart | 33 +++ lib/data/dataoutputs/print_dataoutputs.dart | 233 ++++++++++++++++++ .../void/pages/success_void_page.dart | 8 +- 3 files changed, 273 insertions(+), 1 deletion(-) diff --git a/lib/core/function/app_function.dart b/lib/core/function/app_function.dart index 7a83f33..217d9ca 100644 --- a/lib/core/function/app_function.dart +++ b/lib/core/function/app_function.dart @@ -165,6 +165,39 @@ Future onPrintRecipt( } } +Future onPrinVoidRecipt( + context, { + required Order order, + required List productItemVoid, + required int totalVoid, +}) async { + final receiptPrinter = + await ProductLocalDatasource.instance.getPrinterByCode('receipt'); + final authData = await AuthLocalDataSource().getAuthData(); + final settings = await SettingsLocalDatasource().getTax(); + final outlet = await OutletLocalDatasource().get(); + + if (receiptPrinter != null) { + try { + final printValue = await PrintDataoutputs.instance.printVoidOrder( + order, + authData.user?.name ?? "", + settings.value, + receiptPrinter.paper.toIntegerFromText, + totalVoid, + outlet, + productItemVoid); + await PrinterService() + .printWithPrinter(receiptPrinter, printValue, context); + } catch (e) { + log("Error printing receipt order: $e"); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error printing receipt order: $e')), + ); + } + } +} + Future generateBarcodeAsUint8List(String data) async { // 1. Buat barcode instance (code128, qrCode, dll) final barcode = Barcode.code128(); diff --git a/lib/data/dataoutputs/print_dataoutputs.dart b/lib/data/dataoutputs/print_dataoutputs.dart index ea619ff..6090e0e 100644 --- a/lib/data/dataoutputs/print_dataoutputs.dart +++ b/lib/data/dataoutputs/print_dataoutputs.dart @@ -1002,6 +1002,239 @@ class PrintDataoutputs { return bytes; } + Future> printVoidOrder( + Order order, + String chashierName, + int taxPercentage, + int paper, + int nominalDikembalikan, + Outlet outlet, + List productItemVoid, + ) async { + List bytes = []; + + final profile = await CapabilityProfile.load(); + final generator = + Generator(paper == 58 ? PaperSize.mm58 : PaperSize.mm80, profile); + + bytes += generator.reset(); + + bytes += generator.text(outlet.name ?? "", + styles: const PosStyles( + bold: true, + align: PosAlign.center, + height: PosTextSize.size1, + width: PosTextSize.size1, + )); + + bytes += generator.text(outlet.address ?? "", + styles: const PosStyles(bold: false, align: PosAlign.center)); + bytes += generator.text(outlet.phoneNumber ?? "", + styles: const PosStyles(bold: false, align: PosAlign.center)); + + bytes += generator.text( + paper == 80 + ? '------------------------------------------------' + : '--------------------------------', + styles: const PosStyles(bold: false, align: PosAlign.center)); + + bytes += generator.row([ + PosColumn( + text: DateFormat('dd MMM yyyy').format(DateTime.now()), + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: DateFormat('HH:mm').format(DateTime.now()), + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + bytes += generator.row([ + PosColumn( + text: 'Receipt Number', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: 'JF-${DateFormat('yyyyMMddhhmm').format(DateTime.now())}', + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + + bytes += generator.row([ + PosColumn( + text: 'Order ID', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: Random().nextInt(100000).toString(), + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + bytes += generator.row([ + PosColumn( + text: 'Bill Name', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: order.metadata?['customer_name'] ?? '', + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + bytes += generator.row([ + PosColumn( + text: 'Collected By', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: chashierName, + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + bytes += generator.row([ + PosColumn( + text: 'Status', + width: 8, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: 'Dibatalkan', + width: 4, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + + for (final product in (productItemVoid ?? [])) { + bytes += generator.row([ + PosColumn( + text: '${product.quantity} x ${product.productName}', + width: 8, + styles: const PosStyles(bold: true, align: PosAlign.left), + ), + PosColumn( + text: ((product.totalPrice ?? 0)).currencyFormatRpV2, + width: 4, + styles: const PosStyles(bold: true, align: PosAlign.right), + ), + ]); + } + bytes += generator.text( + paper == 80 + ? '------------------------------------------------' + : '--------------------------------', + styles: const PosStyles(bold: false, align: PosAlign.center)); + + bytes += generator.row([ + PosColumn( + text: 'Subtotal ${productItemVoid.length} Product', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: (order.subtotal ?? 0).currencyFormatRpV2, + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + + bytes += generator.row([ + PosColumn( + text: 'Discount', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: (order.discountAmount ?? 0).currencyFormatRpV2, + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + + // Only show tax if it's greater than 0 + if ((order.taxAmount ?? 0) > 0) { + bytes += generator.row([ + PosColumn( + text: 'Tax PB1 ($taxPercentage%)', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: (order.taxAmount ?? 0).currencyFormatRpV2, + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + } + + // Only show service charge if it's greater than 0 + // if (serviceCharge > 0) { + // bytes += generator.row([ + // PosColumn( + // text: 'Service Charge($serviceChargePercentage%)', + // width: 6, + // styles: const PosStyles(align: PosAlign.left), + // ), + // PosColumn( + // text: serviceCharge.currencyFormatRpV2, + // width: 6, + // styles: const PosStyles(align: PosAlign.right), + // ), + // ]); + // } + bytes += generator.text( + paper == 80 + ? '------------------------------------------------' + : '--------------------------------', + styles: const PosStyles(bold: false, align: PosAlign.center)); + bytes += generator.row([ + PosColumn( + text: 'Total', + width: 6, + styles: const PosStyles(bold: true, align: PosAlign.left), + ), + PosColumn( + text: '${order.totalAmount ?? ""}'.currencyFormatRpV2, + width: 6, + styles: const PosStyles(bold: true, align: PosAlign.right), + ), + ]); + bytes += generator.row([ + PosColumn( + text: 'Dikembalikan', + width: 6, + styles: const PosStyles(align: PosAlign.left), + ), + PosColumn( + text: nominalDikembalikan.currencyFormatRpV2, + width: 6, + styles: const PosStyles(align: PosAlign.right), + ), + ]); + bytes += generator.text( + paper == 80 + ? '------------------------------------------------' + : '--------------------------------', + styles: const PosStyles(bold: false, align: PosAlign.center)); + // bytes += generator.text('Notes', + // styles: const PosStyles(bold: false, align: PosAlign.center)); + // bytes += generator.text('Pass Wifi: fic14jilid2', + // styles: const PosStyles(bold: false, align: PosAlign.center)); + // //terima kasih + // bytes += generator.text('Terima Kasih', + // styles: const PosStyles(bold: true, align: PosAlign.center)); + paper == 80 ? bytes += generator.feed(3) : bytes += generator.feed(1); + bytes += generator.cut(); + return bytes; + } + Future> printQRIS( int totalPrice, Uint8List imageQris, int paper) async { List bytes = []; diff --git a/lib/presentation/void/pages/success_void_page.dart b/lib/presentation/void/pages/success_void_page.dart index c740d9c..d34f2f2 100644 --- a/lib/presentation/void/pages/success_void_page.dart +++ b/lib/presentation/void/pages/success_void_page.dart @@ -3,6 +3,7 @@ import 'package:enaklo_pos/core/components/spaces.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart'; +import 'package:enaklo_pos/core/function/app_function.dart'; import 'package:enaklo_pos/presentation/home/pages/dashboard_page.dart'; import 'package:enaklo_pos/presentation/void/painter/pattern_painter.dart'; import 'package:flutter/material.dart'; @@ -632,5 +633,10 @@ class _SuccessVoidPageState extends State ); } - void _printVoidReceipt() {} + void _printVoidReceipt() { + onPrinVoidRecipt(context, + order: widget.voidedOrder, + productItemVoid: widget.voidedItems ?? [], + totalVoid: widget.voidAmount); + } }