import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; import '../../data/models/tank_model.dart'; import '../tanklist/tanklist_view.dart'; class PrintController extends GetxController { final argunments = Get.arguments; final List tankList = Get.arguments['tankList'] ?? []; final String year = Get.arguments['year'] ?? 'NoYear'; final String summeLiter = Get.arguments['summeLiter'] ?? '0.0'; final String summePreis = Get.arguments['summePreis'] ?? '0.0'; Future printPdfReport() async { final doc = pw.Document(); final font = await PdfGoogleFonts.robotoRegular(); final List tankungen = tankList.map((e) => AppWriteTankModel.fromMap(e)).toList(); // Daten nach Monat gruppieren final dFormat = DateFormat('MMMM yyyy', 'de'); final Map> tankungenByMonth = {}; for (var tankung in tankungen) { final month = dFormat.format(DateTime.parse(tankung.date)); if (!tankungenByMonth.containsKey(month)) { tankungenByMonth[month] = []; } tankungenByMonth[month]!.add(tankung); } doc.addPage( pw.Page( pageFormat: PdfPageFormat.a4.copyWith( marginBottom: 1.0 * PdfPageFormat.cm, marginLeft: 1.0 * PdfPageFormat.cm, marginRight: 1.0 * PdfPageFormat.cm, marginTop: 1.0 * PdfPageFormat.cm), build: (pw.Context context) { return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ //Header // PDF-Design hier pw.Text('Tankbericht $year', style: pw.TextStyle( fontSize: 24, fontWeight: pw.FontWeight.bold, color: PdfColors.blue900, font: font)), pw.SizedBox(height: 10), pw.Text('Alle Tankungen im Überblick', style: pw.TextStyle( fontSize: 16, color: PdfColors.grey700, font: font)), pw.Divider(color: PdfColors.grey400), pw.SizedBox(height: 20), // Data // Dynamische Erstellung der monatlichen Abschnitte ...tankungenByMonth.entries.map((entry) { final monthName = entry.key; final monthlyData = entry.value; // Monatliche Summen berechnen final double monthlyLiters = monthlyData.fold( 0.0, (sum, item) => sum + double.parse(item.liters)); final double monthlyPrice = monthlyData.fold( 0.0, (sum, item) => sum + double.parse(item.szSummePreis ?? '0.0')); final double monthlyAvrLiterPrice = monthlyPrice / monthlyLiters; // Monatlicher Abschnitt // Erstelle die Datenzeilen final List> tableData = monthlyData.map((item) { var modDate = item.date.substring(5); var modPreisPerLiter = item.pricePerLiter.padRight(5, '0'); return [ modDate, item.location, item.liters, modPreisPerLiter, item.szSummePreis ?? '0.0', item.odometer ]; }).toList(); var monthAvrPricePerLiter = monthlyAvrLiterPrice.toStringAsFixed(3); // Füge die Summenzeile hinzu tableData.add([ 'Summe', '', // Leere Zelle für Ort (monthlyLiters.toStringAsFixed(2)), '$monthAvrPricePerLiter Ø', // Leere Zelle für Preis/L (monthlyPrice.toStringAsFixed(2)), '' ]); return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ // Monatsüberschrift pw.Text( monthName, style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 18, font: font, ), ), pw.SizedBox(height: 10), // Tabelle für den jeweiligen Monat // pw.TableHelper.fromTextArray( // headers: [ // 'Datum', // 'Ort', // 'Menge (L)', // 'Preis/L (€)', // 'Summe (€)', // 'KM-Stand' // ], // cellAlignment: pw.Alignment.centerLeft, // border: pw.TableBorder.all(color: PdfColors.grey200), // headerStyle: pw.TextStyle( // fontWeight: pw.FontWeight.bold, font: font), // data: tableData, // cellStyle: pw.TextStyle(font: font), // ), // Manuelle Erstellung der Tabelle mit individueller Formatierung pw.Table( border: pw.TableBorder.all(color: PdfColors.grey200), columnWidths: { 0: const pw.FlexColumnWidth(1.0), // Datum 1: const pw.FlexColumnWidth(4.0), // Ort 2: const pw.FlexColumnWidth(1.3), // Menge 3: const pw.FlexColumnWidth(1.3), // Preis/L 4: const pw.FlexColumnWidth(1.4), // Summe 5: const pw.FlexColumnWidth(1.3), // KM-Stand }, children: [ // Kopfzeile mit grauem Hintergrund pw.TableRow( decoration: const pw.BoxDecoration(color: PdfColors.grey200), children: [ _buildHeaderCell('Datum', font), _buildHeaderCell('Ort', font), _buildHeaderCell('Menge(L)', font), _buildHeaderCell('Preis/L(€)', font), _buildHeaderCell('Summe(€)', font), _buildHeaderCell('Km-Stand', font), ], ), // Datenzeilen ...monthlyData.map((item) { var modDate = item.date.substring(5); var modPreisPerLiter = item.pricePerLiter.padRight(5, '0'); return pw.TableRow( children: [ _buildDataCell(modDate, font), _buildDataCell(item.location, font), _buildDataCell(item.liters, font), _buildDataCell(modPreisPerLiter, font), _buildDataCell(item.szSummePreis!, font), _buildDataCell(item.odometer, font), ], ); }), // Summenzeile mit ANDERER grauem Hintergrund pw.TableRow( decoration: const pw.BoxDecoration(color: PdfColors.grey300), children: [ _buildDataCell('', font), _buildDataCell('Gesamt Summe Monat', font), _buildDataCell('${monthlyLiters.toStringAsFixed(2)} L', font), _buildDataCell('$monthAvrPricePerLiter Ø', font), _buildDataCell('${monthlyPrice.toStringAsFixed(2)} €', font), _buildDataCell('', font) ], ), ], ), pw.SizedBox(height: 20), ], ); }), //footer pw.Spacer(), pw.Divider(color: PdfColors.grey400), pw.Container( alignment: pw.Alignment.centerRight, child: pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.end, children: [ pw.Text('Jahres-Gesamtmenge: $summeLiter L', style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 16, font: font)), pw.Text('Jahres-Gesamtsumme: $summePreis €', style: pw.TextStyle( fontWeight: pw.FontWeight.bold, fontSize: 16, color: PdfColors.blue700, font: font)), ], ), ), ], ); }, ), ); // Druckansicht öffnen await Printing.layoutPdf( onLayout: (PdfPageFormat format) async => doc.save(), ); } void goToTankListPage() async { await Get.offAndToNamed(TanklistPage.namedRoute); } // Hilfs-Widgets für die Zellen pw.Widget _buildHeaderCell(String text, pw.Font font) { return pw.Container( alignment: pw.Alignment.centerLeft, padding: const pw.EdgeInsets.symmetric(vertical: 5, horizontal: 8), child: pw.Text( text, style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: font), ), ); } pw.Widget _buildDataCell(String text, pw.Font font, {bool alignRight = false}) { return pw.Container( alignment: alignRight ? pw.Alignment.centerRight : pw.Alignment.centerLeft, padding: const pw.EdgeInsets.symmetric(vertical: 5, horizontal: 8), child: pw.Text( text, style: pw.TextStyle(font: font), ), ); } }