101 lines
4.8 KiB
Dart
101 lines
4.8 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart' show rootBundle;
|
|
import 'package:intl/intl.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart' as pw;
|
|
|
|
import '../models/shipment_models.dart';
|
|
import 'company_repository.dart';
|
|
|
|
class ShippingLabelService {
|
|
ShippingLabelService({CompanyRepository? companyRepository})
|
|
: _companyRepository = companyRepository ?? CompanyRepository();
|
|
|
|
final CompanyRepository _companyRepository;
|
|
|
|
Future<String?> generateLabel(Shipment shipment) async {
|
|
try {
|
|
final company = await _companyRepository.getCompanyInfo();
|
|
final fontData = await rootBundle.load('assets/fonts/ipaexg.ttf');
|
|
final ipaex = pw.Font.ttf(fontData);
|
|
final dateFormat = DateFormat('yyyy/MM/dd');
|
|
|
|
final pdf = pw.Document();
|
|
pdf.addPage(
|
|
pw.Page(
|
|
pageFormat: PdfPageFormat.a5,
|
|
margin: const pw.EdgeInsets.all(20),
|
|
build: (context) {
|
|
return pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text('出荷ラベル', style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.SizedBox(height: 8),
|
|
pw.Text('発行日: ${dateFormat.format(DateTime.now())}', style: pw.TextStyle(font: ipaex)),
|
|
pw.Divider(),
|
|
pw.Text('差出人', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.Text(company.name, style: pw.TextStyle(font: ipaex)),
|
|
if (company.address != null) pw.Text(company.address!, style: pw.TextStyle(font: ipaex)),
|
|
if (company.tel != null) pw.Text('TEL: ${company.tel}', style: pw.TextStyle(font: ipaex)),
|
|
pw.SizedBox(height: 12),
|
|
pw.Text('宛先', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.Text(shipment.customerNameSnapshot ?? '取引先未設定', style: pw.TextStyle(fontSize: 16, font: ipaex)),
|
|
if (shipment.orderNumberSnapshot != null)
|
|
pw.Text('受注番号: ${shipment.orderNumberSnapshot}', style: pw.TextStyle(font: ipaex)),
|
|
pw.SizedBox(height: 12),
|
|
pw.Text('配送情報', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.Text('配送業者: ${shipment.carrierName ?? '-'}', style: pw.TextStyle(font: ipaex)),
|
|
pw.Text('追跡番号: ${shipment.trackingNumber ?? '-'}', style: pw.TextStyle(font: ipaex)),
|
|
if (shipment.trackingUrl != null && shipment.trackingUrl!.isNotEmpty)
|
|
pw.Text('追跡URL: ${shipment.trackingUrl}', style: pw.TextStyle(font: ipaex)),
|
|
pw.SizedBox(height: 12),
|
|
pw.Text('出荷明細', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.SizedBox(height: 6),
|
|
if (shipment.items.isEmpty)
|
|
pw.Text('明細登録なし', style: pw.TextStyle(font: ipaex))
|
|
else
|
|
pw.TableHelper.fromTextArray(
|
|
headers: const ['品目', '数量'],
|
|
data: shipment.items
|
|
.map(
|
|
(item) => [
|
|
item.description,
|
|
item.quantity.toString(),
|
|
],
|
|
)
|
|
.toList(),
|
|
headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex),
|
|
cellStyle: pw.TextStyle(font: ipaex),
|
|
columnWidths: const {
|
|
0: pw.FlexColumnWidth(3),
|
|
1: pw.FlexColumnWidth(1),
|
|
},
|
|
),
|
|
if (shipment.notes?.isNotEmpty == true) ...[
|
|
pw.SizedBox(height: 12),
|
|
pw.Text('備考', style: pw.TextStyle(fontWeight: pw.FontWeight.bold, font: ipaex)),
|
|
pw.Text(shipment.notes!, style: pw.TextStyle(font: ipaex)),
|
|
],
|
|
],
|
|
);
|
|
},
|
|
),
|
|
);
|
|
|
|
final directory = await getApplicationDocumentsDirectory();
|
|
final timestamp = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now());
|
|
final orderFragment = shipment.orderNumberSnapshot ?? shipment.id.substring(0, 6);
|
|
final fileName = 'shipping_label_${orderFragment}_$timestamp.pdf';
|
|
final file = File(p.join(directory.path, fileName));
|
|
await file.writeAsBytes(await pdf.save());
|
|
return file.path;
|
|
} catch (e) {
|
|
debugPrint('Shipping label generation failed: $e');
|
|
return null;
|
|
}
|
|
}
|
|
}
|