import 'package:flutter/widgets.dart' show AssetImage; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; import '../../models/document_model.dart'; class PdfService { static Future generateAndPrintReceipt(DocumentModel document) async { final pdf = pw.Document(); // Load PFM logo asset final logoImage = await flutterImageProvider(const AssetImage('assets/logo.png')); final isProductScan = document.docType == 'Product'; // Add page pdf.addPage( pw.Page( pageFormat: PdfPageFormat.a4, build: (pw.Context context) { return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ // Header & Title pw.Row( mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, children: [ pw.Text( isProductScan ? 'BUKTI VERIFIKASI SCAN PRODUK' : 'TANDA TERIMA PENGIRIMAN', style: pw.TextStyle(fontSize: 22, fontWeight: pw.FontWeight.bold) ), pw.SizedBox( width: 60, height: 60, child: pw.Image(logoImage), ), ] ), pw.SizedBox(height: 20), // Document Headers pw.Container( padding: const pw.EdgeInsets.all(10), decoration: pw.BoxDecoration( border: pw.Border.all(color: PdfColors.grey), borderRadius: const pw.BorderRadius.all(pw.Radius.circular(8)), ), child: pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: isProductScan ? [ _buildTextRow('Tanggal Scan', document.tanggal), _buildTextRow('Toko / Cabang', document.kepadaYth), _buildTextRow('Jenis Verifikasi', 'Pemindaian Produk & Kadaluwarsa'), ] : [ _buildTextRow('Tanggal', document.tanggal), _buildTextRow('No PO', document.noPo), _buildTextRow('No SO', document.noSo), _buildTextRow('No DO', document.noDo), ] ), ), pw.SizedBox(height: 20), // Detail Scan / Pengiriman Section pw.Text( isProductScan ? 'Informasi Verifikasi' : 'Detail Pengiriman', style: pw.TextStyle(fontSize: 16, fontWeight: pw.FontWeight.bold) ), pw.SizedBox(height: 8), pw.Container( padding: const pw.EdgeInsets.all(10), decoration: pw.BoxDecoration( color: PdfColors.grey100, borderRadius: const pw.BorderRadius.all(pw.Radius.circular(8)), ), child: pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: isProductScan ? [ _buildTextRow('Nama Produk', document.items.isNotEmpty ? document.items.first.namaBarang : '-'), _buildTextRow('Kode SKU', document.items.isNotEmpty ? document.items.first.nomorSku : '-'), _buildTextRow('Nomor Batch', document.noDo), _buildTextRow('Tanggal Expired', document.alamat.replaceAll("Product Scan: Expired ", "")), ] : [ _buildTextRow('Kepada Yth', document.kepadaYth), _buildTextRow('Order Untuk', document.orderUntuk), _buildTextRow('Alamat', document.alamat), _buildTextRow('Plat Truk', document.platTruk), _buildTextRow('Nama Driver', document.namaDriver), ] ), ), pw.SizedBox(height: 20), // Items Table / Scanned Product Details pw.Text( isProductScan ? 'Detail Item Scanned' : 'Barang Dikirim', style: pw.TextStyle(fontSize: 16, fontWeight: pw.FontWeight.bold) ), pw.SizedBox(height: 8), isProductScan ? pw.Table.fromTextArray( context: context, border: pw.TableBorder.all(color: PdfColors.grey), headerDecoration: const pw.BoxDecoration(color: PdfColors.grey300), headerHeight: 25, cellHeight: 25, columnWidths: { 0: const pw.FixedColumnWidth(100), // SKU 1: const pw.FlexColumnWidth(2), // Nama Barang 2: const pw.FixedColumnWidth(100), // Batch 3: const pw.FixedColumnWidth(100), // Expired }, cellAlignments: { 0: pw.Alignment.centerLeft, 1: pw.Alignment.centerLeft, 2: pw.Alignment.center, 3: pw.Alignment.center, }, headers: ['Nomor SKU', 'Nama Barang', 'Nomor Batch', 'Expired Date'], data: [ [ document.items.isNotEmpty ? document.items.first.nomorSku : '-', document.items.isNotEmpty ? document.items.first.namaBarang : '-', document.noDo, document.alamat.replaceAll("Product Scan: Expired ", ""), ] ], ) : pw.Table.fromTextArray( context: context, border: pw.TableBorder.all(color: PdfColors.grey), headerDecoration: const pw.BoxDecoration(color: PdfColors.grey300), headerHeight: 25, cellHeight: 25, columnWidths: { 0: const pw.FixedColumnWidth(80), // SKU 1: const pw.FlexColumnWidth(2), // Nama Barang 2: const pw.FixedColumnWidth(70), // Banyak 3: const pw.FixedColumnWidth(70), // Jumlah }, cellAlignments: { 0: pw.Alignment.centerLeft, 1: pw.Alignment.centerLeft, 2: pw.Alignment.centerRight, 3: pw.Alignment.centerRight, }, headers: ['Nomor SKU', 'Nama Barang', 'Banyak', 'Jumlah'], data: document.items.map((item) { return [ item.nomorSku, item.namaBarang, item.banyak, item.jumlah, ]; }).toList(), ), pw.Spacer(), // Footer & Signatures pw.Row( mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, children: isProductScan ? [ pw.Column( children: [ pw.SizedBox(height: 40), pw.Text('_______________________', style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 4), pw.Text('Petugas / Staff Toko'), ] ), pw.Column( children: [ pw.SizedBox(height: 40), pw.Text('_______________________', style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 4), pw.Text('Penanggung Jawab Toko'), ] ) ] : [ pw.Column( children: [ pw.SizedBox(height: 40), pw.Text(document.namaDriver.isNotEmpty ? document.namaDriver : '_______________________', style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 4), pw.Text('Pengirim (Driver)'), ] ), pw.Column( children: [ pw.SizedBox(height: 40), pw.Text(document.namaPenerima.isNotEmpty ? document.namaPenerima : '_______________________', style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 4), pw.Text('Penerima (Penjaga Toko)'), ] ) ] ) ], ); }, ), ); // Prompt user to view/print/save the PDF natively await Printing.layoutPdf( onLayout: (PdfPageFormat format) async => pdf.save(), format: PdfPageFormat.a4, name: isProductScan ? 'ProductScan_${document.items.isNotEmpty ? document.items.first.nomorSku : "unknown"}' : 'Document_${document.noDo.replaceAll('/', '_')}', ); } static pw.Widget _buildTextRow(String label, String value) { return pw.Padding( padding: const pw.EdgeInsets.symmetric(vertical: 2), child: pw.Row( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ pw.SizedBox(width: 100, child: pw.Text(label, style: pw.TextStyle(fontWeight: pw.FontWeight.bold))), pw.Expanded( child: pw.Text(': $value', softWrap: true), ), ] ) ); } }