85 lines
3.1 KiB
Dart
85 lines
3.1 KiB
Dart
import 'dart:typed_data';
|
||
|
||
import 'package:intl/intl.dart';
|
||
import 'package:pdf/pdf.dart';
|
||
import 'package:pdf/widgets.dart' as pw;
|
||
|
||
import 'fuel_report.dart';
|
||
|
||
final _dateFormat = DateFormat.yMMMd();
|
||
final _currencyFormat = NumberFormat.simpleCurrency();
|
||
|
||
/// Renders [report] as a single-page-friendly PDF: a per-vehicle table
|
||
/// (VIN, nickname, entry count, gallons, total cost) plus a grand-total
|
||
/// row, suitable for attaching to a fuel tax refund submission or handing
|
||
/// to a printer.
|
||
Future<Uint8List> buildFuelReportPdf(FuelReport report) async {
|
||
final doc = pw.Document();
|
||
|
||
doc.addPage(
|
||
pw.MultiPage(
|
||
pageFormat: PdfPageFormat.letter,
|
||
header: (context) => pw.Column(
|
||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||
children: [
|
||
pw.Text('Fuel Report', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
|
||
pw.Text(
|
||
'${_dateFormat.format(report.startDate)} – ${_dateFormat.format(report.endDate)}',
|
||
style: const pw.TextStyle(fontSize: 12, color: PdfColors.grey700),
|
||
),
|
||
pw.SizedBox(height: 16),
|
||
],
|
||
),
|
||
build: (context) => [
|
||
if (report.rows.isEmpty)
|
||
pw.Text('No vehicles had a receipted fuel entry in this date range.')
|
||
else
|
||
pw.TableHelper.fromTextArray(
|
||
headers: ['Vehicle', 'VIN', 'Entries', 'Gallons', 'Total Cost'],
|
||
data: [
|
||
for (final row in report.rows)
|
||
[
|
||
row.vehicle.nickname?.trim().isNotEmpty == true ? row.vehicle.nickname! : '—',
|
||
row.vehicle.vin,
|
||
row.entryCount.toString(),
|
||
row.totalGallons.toStringAsFixed(3),
|
||
_currencyFormat.format(row.totalCost),
|
||
],
|
||
],
|
||
cellAlignments: const {
|
||
2: pw.Alignment.centerRight,
|
||
3: pw.Alignment.centerRight,
|
||
4: pw.Alignment.centerRight,
|
||
},
|
||
headerAlignments: const {
|
||
2: pw.Alignment.centerRight,
|
||
3: pw.Alignment.centerRight,
|
||
4: pw.Alignment.centerRight,
|
||
},
|
||
headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||
cellPadding: const pw.EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||
),
|
||
pw.SizedBox(height: 12),
|
||
pw.Divider(),
|
||
pw.Row(
|
||
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
pw.Text('Total', style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
|
||
pw.Text(
|
||
'${report.totalGallons.toStringAsFixed(3)} gal · ${_currencyFormat.format(report.totalCost)}',
|
||
style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
);
|
||
|
||
return doc.save();
|
||
}
|
||
|
||
/// `fuel-report-<start>-<end>.pdf`, e.g. `fuel-report-20260101-20260331.pdf`.
|
||
String fuelReportFileName(FuelReport report) {
|
||
final fmt = DateFormat('yyyyMMdd');
|
||
return 'fuel-report-${fmt.format(report.startDate)}-${fmt.format(report.endDate)}.pdf';
|
||
}
|