import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import '../../models/models.dart'; import 'package:printing/printing.dart'; import 'package:flutter/services.dart' show rootBundle; Future imprimirTicketsJuntos(Pedido pedido) async { final pdf = pw.Document(); final image = pw.MemoryImage( (await rootBundle.load('assets/JoshiLogo-BN.png')).buffer.asUint8List(), ); pdf.addPage( generarPaginaPrimerTicket(pedido, image), ); pdf.addPage( generarPaginaSegundoTicket(pedido), ); await printPdf(Uint8List.fromList(await pdf.save())); } pw.Page generarPaginaPrimerTicket(Pedido pedido, pw.MemoryImage image) { final numberFormat = NumberFormat('#,##0.00', 'es_MX'); return pw.Page( pageFormat: PdfPageFormat.roll57, build: (pw.Context context) { double total = 0; final productList = pedido.productos .map( (producto) { final productPrice = double.parse(producto.producto?.precio ?? '0'); final productTotal = productPrice * (producto.cantidad ?? 1); final toppingsList = producto.toppings.where((topping) { final toppingPrice = double.parse(topping.topping?.precio ?? '0'); return toppingPrice > 0; }).map((topping) { final toppingPrice = double.parse(topping.topping?.precio ?? '0'); total += toppingPrice * (producto.cantidad ?? 1); return pw.Row( children: [ pw.Text( '- ${topping.topping?.nombre ?? "Topping no especificado"}', style: const pw.TextStyle(fontSize: 7)), pw.Spacer(), pw.Text('\$${numberFormat.format(toppingPrice)}', style: const pw.TextStyle(fontSize: 7)), ], ); }).toList(); total += productTotal; return [ pw.Row( mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, children: [ pw.Expanded( flex: 2, child: pw.Text( producto.producto?.nombre ?? "Producto no especificado", style: const pw.TextStyle(fontSize: 7)), ), pw.Expanded( flex: 1, child: pw.Text('x${producto.cantidad}', style: const pw.TextStyle(fontSize: 7)), ), pw.Padding( padding: pw.EdgeInsets.only(right: 2), child: pw.Expanded( flex: 1, child: pw.Text( '\$${numberFormat.format(productPrice)}', style: const pw.TextStyle(fontSize: 8)), ), ) ], ), ...toppingsList, ]; }, ) .expand((e) => e) .toList(); return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.center, children: [ pw.Padding( padding: const pw.EdgeInsets.only(right: 15), child: pw.Center(child: pw.Image(image, width: 50, height: 50))), pw.SizedBox(height: 10), pw.Padding( padding: const pw.EdgeInsets.only(right: 15), child: pw.Column(children: [ pw.Padding( padding: pw.EdgeInsets.only(left: 10), child: pw.Text('Joshi Papas Tu Sabor tu Estilo', style: pw.TextStyle( fontSize: 12, fontWeight: pw.FontWeight.bold))), pw.SizedBox(height: 10), pw.Text('Fecha: ${pedido.peticion}', style: const pw.TextStyle(fontSize: 9)), pw.Text('JoshiPapas', style: const pw.TextStyle(fontSize: 9)), pw.Text('Chihuahua', style: const pw.TextStyle(fontSize: 9)), ])), pw.SizedBox(height: 10), pw.Text('Pedido: ${pedido.folio}', style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 10)), pw.SizedBox(height: 10), pw.Padding( padding: const pw.EdgeInsets.only(right: 20), child: pw.Column(children: productList)), pw.Divider(), pw.Row( mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, children: [ pw.Text('Total:', style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 9)), pw.Padding( padding: const pw.EdgeInsets.only(right: 30), child: pw.Text('\$${numberFormat.format(total)}', style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 9)), ), ], ), pw.SizedBox(height: 5), pw.Padding( padding: const pw.EdgeInsets.only(right: 15), child: pw.Text('¡GRACIAS POR SU COMPRA!', style: pw.TextStyle( fontSize: 8, fontWeight: pw.FontWeight.bold))), pw.Divider(), pw.SizedBox(height: 20), pw.Text('.', style: pw.TextStyle(fontSize: 1)), ]); }); } pw.Page generarPaginaSegundoTicket(Pedido pedido) { return pw.Page( pageFormat: PdfPageFormat.roll57, build: (pw.Context context) { List content = [ pw.SizedBox(height: 20), pw.Text('.', style: pw.TextStyle(fontSize: 1)), pw.Padding( padding: const pw.EdgeInsets.only(right: 15), child: pw.Text('Fecha: ${pedido.peticion}', style: pw.TextStyle( fontSize: 9, fontWeight: pw.FontWeight.bold))), pw.SizedBox(height: 5), pw.Text('Pedido: ${pedido.folio}', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)), pw.SizedBox(height: 10), pw.Text('Cliente: ${pedido.nombreCliente}', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9)), pw.SizedBox(height: 10), ]; content.addAll(pedido.productos .map((producto) { final productPrice = double.parse(producto.producto?.precio ?? '0'); final productTotal = productPrice * (producto.cantidad ?? 1); final toppingsList = producto.toppings.map((topping) { return pw.Row( children: [ pw.Text( '-${topping.topping?.nombre ?? "Topping no especificado"}', style: const pw.TextStyle(fontSize: 7)), ], ); }).toList(); return [ pw.Row( mainAxisAlignment: pw.MainAxisAlignment.start, children: [ pw.Expanded( flex: 3, child: pw.Text( producto.producto?.nombre ?? "Producto no especificado", style: const pw.TextStyle(fontSize: 9)), ), pw.Expanded( flex: 1, child: pw.Text('x${producto.cantidad}', style: const pw.TextStyle(fontSize: 9)), ), ], ), ...toppingsList, ]; }) .expand((e) => e) .toList()); if (pedido.comentarios != null && pedido.comentarios!.isNotEmpty) { content.add(pw.SizedBox(height: 10)); content.add(pw.Text('Comentarios:', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, fontSize: 9))); content.add(pw.Padding( padding: const pw.EdgeInsets.only(right: 15), child: pw.Text(pedido.comentarios!, style: const pw.TextStyle(fontSize: 9)), )); content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1))); content.add(pw.SizedBox(height: 20)); content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1))); } content.add(pw.Text('.', style: pw.TextStyle(fontSize: 1))); return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.center, children: content); }); } Future printPdf(Uint8List pdfBytes) async { await Printing.layoutPdf( onLayout: (PdfPageFormat format) => pdfBytes, ); }