// lib/screens/invoice_detail_page.dart import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import '../models/invoice_models.dart'; import '../services/pdf_generator.dart'; /// 伝票詳細を表示・編集する画面 class InvoiceDetailPage extends StatefulWidget { final Invoice invoice; const InvoiceDetailPage({ Key? key, required this.invoice, }) : super(key: key); @override State createState() => _InvoiceDetailPageState(); } class _InvoiceDetailPageState extends State { late Invoice _currentInvoice; final _descriptionController = TextEditingController(); final _quantityController = TextEditingController(); final _unitPriceController = TextEditingController(); bool _isLoading = false; @override void initState() { super.initState(); _currentInvoice = widget.invoice; } @override void dispose() { _descriptionController.dispose(); _quantityController.dispose(); _unitPriceController.dispose(); super.dispose(); } /// 明細を追加 void _addItem() { setState(() { _currentInvoice = _currentInvoice.copyWith( items: [ ..._currentInvoice.items, InvoiceItem( description: "新規明細", quantity: 1, unitPrice: 10000, ) ] ); }); } /// 明細を削除 void _removeItem(int index) { setState(() { final newItems = List.from(_currentInvoice.items); newItems.removeAt(index); _currentInvoice = _currentInvoice.copyWith(items: newItems); }); } /// 明細を更新 void _updateItem(int index, InvoiceItem item) { setState(() { final newItems = List.from(_currentInvoice.items); newItems[index] = item; _currentInvoice = _currentInvoice.copyWith(items: newItems); }); } /// PDFを再生成 Future _regeneratePdf() async { setState(() => _isLoading = true); final path = await generateInvoicePdf(_currentInvoice); if (path != null) { final updatedInvoice = _currentInvoice.copyWith(filePath: path); // TODO: Repositoryで保存 if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('PDFを更新しました')), ); } } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('PDFの生成に失敗しました')), ); } } setState(() => _isLoading = false); } @override Widget build(BuildContext context) { final amountFormatter = NumberFormat("#,###"); final dateFormatter = DateFormat('yyyy/MM/dd'); return Scaffold( appBar: AppBar( title: Text("${_currentInvoice.type.label}詳細"), backgroundColor: Colors.blueGrey, foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.share), onPressed: () { // TODO: 共有機能 }, ), IconButton( icon: const Icon(Icons.print), onPressed: _regeneratePdf, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 基本情報 Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "基本情報", style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text("種類: ${_currentInvoice.type.label}"), Text("顧客: ${_currentInvoice.customer.formalName}"), Text("日付: ${dateFormatter.format(_currentInvoice.date)}"), Text("番号: ${_currentInvoice.invoiceNumber}"), if (_currentInvoice.notes != null) Text("備考: ${_currentInvoice.notes}"), ], ), ), ), const SizedBox(height: 16), // 明細リスト Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "明細", style: Theme.of(context).textTheme.titleLarge, ), TextButton.icon( onPressed: _addItem, icon: const Icon(Icons.add), label: const Text("明細追加"), ), ], ), const SizedBox(height: 8), ..._currentInvoice.items.asMap().entries.map((entry) { final index = entry.key; final item = entry.value; return Padding( padding: const EdgeInsets.only(bottom: 8.0), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.description, style: const TextStyle(fontWeight: FontWeight.bold), ), Text( "${item.quantity} × ¥${amountFormatter.format(item.unitPrice)}", style: TextStyle( color: item.isDiscount ? Colors.red : null, decoration: item.isDiscount ? TextDecoration.lineThrough : null, ), ), ], ), ), Text( "¥${amountFormatter.format(item.subtotal)}", style: TextStyle( fontWeight: FontWeight.bold, color: item.isDiscount ? Colors.red : null, ), ), IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => _removeItem(index), ), ], ), ); }).toList(), ], ), ), ), const SizedBox(height: 16), // 合計 Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text("小計: ¥${amountFormatter.format(_currentInvoice.subtotal)}"), Text("消費税: ¥${amountFormatter.format(_currentInvoice.tax)}"), Text( "合計: ¥${amountFormatter.format(_currentInvoice.totalAmount)}", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), ), ), ], ), ), ); } }