Files
app-grosir/lib/services/export_service.dart
2026-07-23 22:12:32 +07:00

167 lines
6.2 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
class ExportService {
static final ExportService _instance = ExportService._internal();
factory ExportService() => _instance;
ExportService._internal();
Future<String?> exportToPdf(List<Map<String, dynamic>> transactions,
String storeName, DateTimeRange? dateRange) async {
try {
debugPrint('exportToPdf called with ${transactions.length} transactions');
final pdf = pw.Document();
pdf.addPage(
pw.Page(
build: (context) {
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text(storeName, style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)),
pw.SizedBox(height: 8),
if (dateRange != null)
pw.Text('${_formatDate(dateRange.start)} - ${_formatDate(dateRange.end)}',
style: pw.TextStyle(fontSize: 12)),
pw.SizedBox(height: 16),
pw.Table(
border: pw.TableBorder.all(),
children: [
pw.TableRow(
children: [
pw.Padding(padding: pw.EdgeInsets.all(8), child: pw.Text('Tanggal', style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
pw.Padding(padding: pw.EdgeInsets.all(8), child: pw.Text('ID', style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
pw.Padding(padding: pw.EdgeInsets.all(8), child: pw.Text('Total', style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
pw.Padding(padding: pw.EdgeInsets.all(8), child: pw.Text('Bayar', style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
pw.Padding(padding: pw.EdgeInsets.all(8), child: pw.Text('Kembali', style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
],
),
for (final tx in transactions)
pw.TableRow(
children: [
pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(_formatDate(tx['date']))),
pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(tx['id'])),
pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(tx['total'])),
pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(tx['paid'])),
pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(tx['change'])),
],
),
],
),
],
);
},
),
);
Directory? directory;
try {
directory = await getTemporaryDirectory();
debugPrint('PDF using temporary directory: ${directory.path}');
} catch (e) {
debugPrint('getTemporaryDirectory failed for PDF: $e');
return null;
}
final file = File('${directory.path}/laporan_transaksi_${DateTime.now().millisecondsSinceEpoch}.pdf');
try {
await file.writeAsBytes(await pdf.save());
debugPrint('PDF file written: ${file.path}, exists: ${await file.exists()}');
} catch (e) {
debugPrint('Failed to write PDF file: $e');
return null;
}
return file.path;
} catch (e) {
debugPrint('exportToPdf error: $e');
return null;
}
}
Future<String?> exportToCsv(List<Map<String, dynamic>> transactions) async {
try {
debugPrint('=== CSV Export Started ===');
debugPrint('Transactions count: ${transactions.length}');
if (transactions.isEmpty) {
debugPrint('No transactions to export');
return null;
}
final buffer = StringBuffer();
buffer.writeln('Tanggal,ID Transaksi,Total,Bayar,Kembali,Item,Diskon');
for (final tx in transactions) {
final date = _formatDate(tx['date']);
final id = tx['id'];
final total = tx['total'];
final paid = tx['paid'];
final change = tx['change'];
final items = tx['items'] is List ? (tx['items'] as List).length : (tx['items'] as int? ?? 0);
final discount = tx['discount'] ?? 0;
buffer.writeln('$date,$id,$total,$paid,$change,$items,$discount');
}
debugPrint('CSV buffer created, length: ${buffer.toString().length}');
String? filePath;
try {
final tempDir = await getTemporaryDirectory();
debugPrint('Temp dir: ${tempDir.path}');
final timestamp = DateTime.now().millisecondsSinceEpoch;
final fileName = 'laporan_transaksi_$timestamp.csv';
filePath = '${tempDir.path}/$fileName';
final file = File(filePath);
await file.writeAsString(buffer.toString());
debugPrint('CSV file written: $filePath');
debugPrint('File exists: ${await file.exists()}');
debugPrint('File size: ${await file.length()}');
} catch (e) {
debugPrint('Error creating CSV file: $e');
return null;
}
debugPrint('=== CSV Export Completed Successfully ===');
return filePath;
} catch (e) {
debugPrint('=== CSV Export Failed ===');
debugPrint('Error: $e');
debugPrint('Stack trace: ${StackTrace.current}');
return null;
}
}
Future<void> shareFile(String filePath) async {
try {
debugPrint('Sharing file: $filePath');
final file = File(filePath);
final exists = await file.exists();
debugPrint('File exists: $exists, size: ${exists ? await file.length() : 0}');
if (!exists) {
debugPrint('File does not exist, cannot share');
return;
}
await Share.shareXFiles([XFile(filePath)], text: 'Laporan Transaksi');
debugPrint('Share completed');
} catch (e) {
debugPrint('shareFile error: $e');
rethrow;
}
}
String _formatDate(dynamic date) {
if (date is DateTime) {
return '${date.day}/${date.month}/${date.year}';
}
return date.toString();
}
}