inv/gemi_invoice/lib/main.dart
2026-01-31 10:50:25 +09:00

81 lines
3.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// version: 1.0.1 (Stable Standalone Edition)
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:path_provider/path_provider.dart';
import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart';
void main() => runApp(const MaterialApp(home: InvoiceApp()));
class InvoiceApp extends StatefulWidget {
const InvoiceApp({super.key});
@override
State<InvoiceApp> createState() => _InvoiceAppState();
}
class _InvoiceAppState extends State<InvoiceApp> {
final _clientController = TextEditingController(text: "現場太郎 様");
final _amountController = TextEditingController(text: "1500"); // 10%抜き単価
String _status = "内容を入力してPDFを発行してください";
Future<void> _generateInvoice() async {
final pdf = pw.Document();
final clientName = _clientController.text;
final int unitPrice = int.tryParse(_amountController.text) ?? 0;
// 【こだわり1】10%固定計算
final int tax = (unitPrice * 0.1).floor();
final int total = unitPrice + tax;
final dateStr = DateFormat('yyyy/MM/dd HH:mm').format(DateTime.now());
// PDFの内容超シンプル
pdf.addPage(pw.Page(build: (context) => pw.Column(children: [
pw.Text("Invoice / Receipt", style: pw.TextStyle(fontSize: 40)),
pw.Divider(),
pw.Text("Client: $clientName"),
pw.Text("Date: $dateStr"),
pw.SizedBox(height: 20),
pw.Text("Subtotal: $unitPrice JPY"),
pw.Text("Tax (10%): $tax JPY"),
pw.Text("Total: $total JPY", style: pw.TextStyle(fontWeight: pw.FontWeight.bold)),
])));
// PDFをバイトデータに変換
final Uint8List bytes = await pdf.save();
// 【こだわり2】SHA-256ハッシュ計算
final hash = sha256.convert(bytes).toString().substring(0, 10);
// 【こだわり3】ファイル名に情報を詰め込む
final fileName = "${DateFormat('yyyyMMdd').format(DateTime.now())}_${clientName}_${total}円_hash_$hash.pdf";
// 保存Androidの書類フォルダなど
final directory = await getExternalStorageDirectory();
final file = File("${directory!.path}/$fileName");
await file.writeAsBytes(bytes);
setState(() {
_status = "保存完了!\n場所: ${file.path}\nハッシュ: $hash";
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("現場のじぇみエモン請求書")),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(children: [
TextField(controller: _clientController, decoration: const InputDecoration(labelText: "取引先名")),
TextField(controller: _amountController, decoration: const InputDecoration(labelText: "単価(税抜)")),
const SizedBox(height: 20),
ElevatedButton(onPressed: _generateInvoice, child: const Text("PDF発行 & ハッシュ保存")),
const SizedBox(height: 20),
Text(_status, style: const TextStyle(color: Colors.blue)),
]),
),
);
}
}