81 lines
3.1 KiB
Dart
81 lines
3.1 KiB
Dart
// 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)),
|
||
]),
|
||
),
|
||
);
|
||
}
|
||
}
|