From b11ae890ce76afb5cb127ae37199480ab1e94e55 Mon Sep 17 00:00:00 2001 From: joe Date: Sun, 15 Feb 2026 00:47:04 +0900 Subject: [PATCH] feat: Implement invoice editing, add company registration number to model and PDF, and refine PDF filename generation. --- analyze_output.txt | 139 ++++++++++++++---------- analyze_output_v2.txt | 76 +++++++++++++ lib/models/company_model.dart | 6 + lib/models/invoice_models.dart | 16 +++ lib/screens/invoice_detail_page.dart | 37 ++++++- lib/screens/invoice_history_screen.dart | 13 ++- lib/screens/invoice_input_screen.dart | 129 ++++++++++++++++++---- lib/services/database_helper.dart | 8 +- lib/services/pdf_generator.dart | 17 ++- 目標.md | 19 ++++ 10 files changed, 364 insertions(+), 96 deletions(-) create mode 100644 analyze_output_v2.txt diff --git a/analyze_output.txt b/analyze_output.txt index ef08291..fb5f90a 100644 --- a/analyze_output.txt +++ b/analyze_output.txt @@ -1,62 +1,83 @@ +Resolving dependencies... +Downloading packages... + geolocator 13.0.4 (14.0.2 available) + geolocator_android 4.6.2 (5.0.2 available) + image 4.5.4 (4.7.2 available) + meta 1.17.0 (1.18.1 available) + petitparser 7.0.1 (7.0.2 available) +Got dependencies! +5 packages have newer versions incompatible with dependency constraints. +Try `flutter pub outdated` for more information. Analyzing gemi_invoice_backup2... -warning • The value of the field '_lastGeneratedInvoice' isn't used • lib/main.dart:43:12 • unused_field - error • The body might complete normally, causing 'null' to be returned, but the return type, 'Widget', is a potentially non-nullable type • lib/main.dart:61:10 • body_might_complete_normally -warning • The label 'appBar' isn't used • lib/main.dart:62:7 • unused_label - error • Expected to find ';' • lib/main.dart:65:7 • expected_token - error • Expected an identifier • lib/main.dart:65:8 • missing_identifier - error • Unexpected text ';' • lib/main.dart:65:8 • unexpected_token -warning • The label 'drawer' isn't used • lib/main.dart:66:7 • unused_label - error • Expected to find ';' • lib/main.dart:92:7 • expected_token - error • Expected an identifier • lib/main.dart:92:8 • missing_identifier - error • Unexpected text ';' • lib/main.dart:92:8 • unexpected_token -warning • The label 'body' isn't used • lib/main.dart:94:7 • unused_label - error • Expected to find ';' • lib/main.dart:106:7 • expected_token - error • Expected an identifier • lib/main.dart:106:8 • missing_identifier - error • Expected to find ';' • lib/main.dart:106:8 • expected_token - error • Unexpected text ';' • lib/main.dart:106:8 • unexpected_token - error • Expected an identifier • lib/main.dart:107:5 • missing_identifier - error • Unexpected text ';' • lib/main.dart:107:5 • unexpected_token - info • Unnecessary empty statement • lib/main.dart:107:6 • empty_statements - info • The imported package 'uuid' isn't a dependency of the importing package • lib/models/customer_model.dart:1:8 • depend_on_referenced_packages -warning • Unused import: 'package:uuid/uuid.dart' • lib/models/customer_model.dart:1:8 • unused_import - error • The named parameter 'unitPrice' is required, but there's no corresponding argument • lib/models/invoice_models.dart:30:12 • missing_required_argument - error • The named parameter 'unit_price' isn't defined • lib/models/invoice_models.dart:34:7 • undefined_named_parameter -warning • The value of the local variable 'amountFormatter' isn't used • lib/models/invoice_models.dart:88:11 • unused_local_variable - info • The imported package 'uuid' isn't a dependency of the importing package • lib/screens/customer_picker_modal.dart:3:8 • depend_on_referenced_packages - error • Undefined class 'Customer' • lib/screens/customer_picker_modal.dart:8:18 • undefined_class - info • Parameter 'key' could be a super parameter • lib/screens/customer_picker_modal.dart:10:9 • use_super_parameters - error • The name 'Customer' isn't a type, so it can't be used as a type argument • lib/screens/customer_picker_modal.dart:22:8 • non_type_as_type_argument - error • The name 'Customer' isn't a type, so it can't be used as a type argument • lib/screens/customer_picker_modal.dart:23:8 • non_type_as_type_argument - error • The property 'formalName' can't be unconditionally accessed because the receiver can be 'null' • lib/screens/customer_picker_modal.dart:47:25 • unchecked_use_of_nullable_value - error • The property 'displayName' can't be unconditionally accessed because the receiver can be 'null' • lib/screens/customer_picker_modal.dart:48:22 • unchecked_use_of_nullable_value - info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:77:28 • use_build_context_synchronously - error • Undefined class 'Customer' • lib/screens/customer_picker_modal.dart:87:5 • undefined_class - error • The method 'Customer' isn't defined for the type '_CustomerPickerModalState' • lib/screens/customer_picker_modal.dart:141:19 • undefined_method - info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:150:29 • use_build_context_synchronously - error • Undefined class 'Customer' • lib/screens/customer_picker_modal.dart:164:23 • undefined_class - info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:175:29 • use_build_context_synchronously -warning • Unused import: 'dart:io' • lib/screens/invoice_detail_page.dart:1:8 • unused_import -warning • Unused import: '../models/customer_model.dart' • lib/screens/invoice_detail_page.dart:7:8 • unused_import - info • Parameter 'key' could be a super parameter • lib/screens/invoice_detail_page.dart:16:9 • use_super_parameters - info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_detail_page.dart:120:28 • use_build_context_synchronously - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:128:5 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:128:11 • deprecated_member_use - info • Use a 'SizedBox' to add whitespace to a layout • lib/screens/invoice_detail_page.dart:283:14 • sized_box_for_whitespace - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:327:43 • deprecated_member_use - info • 'shareXFiles' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:327:49 • deprecated_member_use -warning • Unused import: '../models/customer_model.dart' • lib/screens/invoice_history_screen.dart:4:8 • unused_import - info • Parameter 'key' could be a super parameter • lib/screens/invoice_history_screen.dart:10:9 • use_super_parameters - info • The imported package 'uuid' isn't a dependency of the importing package • lib/screens/invoice_input_screen.dart:2:8 • depend_on_referenced_packages - info • Parameter 'key' could be a super parameter • lib/screens/invoice_input_screen.dart:14:9 • use_super_parameters - info • The private field _customerBuffer could be 'final' • lib/screens/invoice_input_screen.dart:29:18 • prefer_final_fields -warning • The value of the field '_customerBuffer' isn't used • lib/screens/invoice_input_screen.dart:29:18 • unused_field - error • A value of type 'Object?' can't be assigned to a variable of type 'Customer?' • lib/screens/invoice_input_screen.dart:87:35 • invalid_assignment - error • The property 'formalName' can't be unconditionally accessed because the receiver can be 'null' • lib/screens/invoice_input_screen.dart:88:49 • unchecked_use_of_nullable_value - error • The property 'formalName' can't be unconditionally accessed because the receiver can be 'null' • lib/screens/invoice_input_screen.dart:89:38 • unchecked_use_of_nullable_value - info • Parameter 'key' could be a super parameter • lib/screens/product_picker_modal.dart:8:9 • use_super_parameters - info • 'desiredAccuracy' is deprecated and shouldn't be used. use settings parameter with AndroidSettings, AppleSettings, WebSettings, or LocationSettings • lib/services/location_service.dart:28:9 • deprecated_member_use - info • 'timeLimit' is deprecated and shouldn't be used. use settings parameter with AndroidSettings, AppleSettings, WebSettings, or LocationSettings • lib/services/location_service.dart:29:9 • deprecated_member_use - info • The import of 'dart:typed_data' is unnecessary because all of the used elements are also provided by the import of 'package:flutter/services.dart' • lib/services/pdf_generator.dart:2:8 • unnecessary_import + info • Parameter 'key' could be a super parameter • lib/screens/activity_log_screen.dart:7:9 • use_super_parameters + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/activity_log_screen.dart:94:34 • deprecated_member_use + info • Parameter 'key' could be a super parameter • lib/screens/barcode_scanner_screen.dart:5:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/company_info_screen.dart:8:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/company_info_screen.dart:63:26 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/company_info_screen.dart:64:19 • use_build_context_synchronously + info • Parameter 'key' could be a super parameter • lib/screens/customer_master_screen.dart:7:9 • use_super_parameters + info • 'value' is deprecated and shouldn't be used. Use initialValue instead. This will set the initial value for the form field. This feature was deprecated after v3.33.0-1.0.pre • lib/screens/customer_master_screen.dart:60:19 • deprecated_member_use + info • The 'child' argument should be last in widget constructor invocations • lib/screens/customer_master_screen.dart:164:9 • sort_child_properties_last + info • Parameter 'key' could be a super parameter • lib/screens/customer_picker_modal.dart:11:9 • use_super_parameters + info • The private field _searchQuery could be 'final' • lib/screens/customer_picker_modal.dart:22:10 • prefer_final_fields +warning • The value of the field '_searchQuery' isn't used • lib/screens/customer_picker_modal.dart:22:10 • unused_field + info • The private field _allCustomers could be 'final' • lib/screens/customer_picker_modal.dart:23:18 • prefer_final_fields +warning • The value of the field '_allCustomers' isn't used • lib/screens/customer_picker_modal.dart:23:18 • unused_field + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:67:28 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:140:29 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:165:29 • use_build_context_synchronously + info • Parameter 'key' could be a super parameter • lib/screens/gps_history_screen.dart:6:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/invoice_detail_page.dart:19:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_detail_page.dart:136:28 • use_build_context_synchronously + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:144:5 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:144:11 • deprecated_member_use + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_detail_page.dart:160:9 • use_build_context_synchronously +warning • Dead code • lib/screens/invoice_detail_page.dart:170:47 • dead_code +warning • The left operand can't be null, so the right operand is never executed • lib/screens/invoice_detail_page.dart:170:50 • dead_null_aware_expression +warning • The left operand can't be null, so the right operand is never executed • lib/screens/invoice_detail_page.dart:171:58 • dead_null_aware_expression +warning • The '!' will have no effect because the receiver can't be null • lib/screens/invoice_detail_page.dart:180:65 • unnecessary_non_null_assertion + error • The method 'InvoiceInputForm' isn't defined for the type '_InvoiceDetailPageState' • lib/screens/invoice_detail_page.dart:230:45 • undefined_method + error • 1 positional argument expected by 'getAllInvoices', but 0 found • lib/screens/invoice_detail_page.dart:240:62 • not_enough_positional_arguments +warning • The value of the local variable 'dateFormatter' isn't used • lib/screens/invoice_detail_page.dart:307:11 • unused_local_variable + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_detail_page.dart:346:114 • deprecated_member_use + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_detail_page.dart:376:84 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:614:13 • deprecated_member_use + info • 'shareXFiles' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:614:19 • deprecated_member_use +warning • The declaration '_SummaryRow' isn't referenced • lib/screens/invoice_detail_page.dart:661:7 • unused_element +warning • A value for optional parameter 'isBold' isn't ever given • lib/screens/invoice_detail_page.dart:664:51 • unused_element_parameter + info • Parameter 'key' could be a super parameter • lib/screens/invoice_history_screen.dart:15:9 • use_super_parameters +warning • The value of the field '_isLoading' isn't used • lib/screens/invoice_history_screen.dart:26:8 • unused_field +warning • The value of the local variable 'amountFormatter' isn't used • lib/screens/invoice_history_screen.dart:97:11 • unused_local_variable +warning • The value of the local variable 'dateFormatter' isn't used • lib/screens/invoice_history_screen.dart:98:11 • unused_local_variable + error • Undefined name 'children' • lib/screens/invoice_history_screen.dart:235:9 • undefined_identifier + error • Expected to find ')' • lib/screens/invoice_history_screen.dart:235:17 • expected_token + error • Expected to find ']' • lib/screens/invoice_history_screen.dart:235:17 • expected_token +warning • Unused import: 'package:uuid/uuid.dart' • lib/screens/invoice_input_screen.dart:2:8 • unused_import + info • Parameter 'key' could be a super parameter • lib/screens/invoice_input_screen.dart:20:9 • use_super_parameters +warning • The value of the field '_status' isn't used • lib/screens/invoice_input_screen.dart:41:10 • unused_field + info • The private field _signaturePath could be 'final' • lib/screens/invoice_input_screen.dart:44:17 • prefer_final_fields + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:137:30 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:141:28 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:142:21 • use_build_context_synchronously + error • The method 'copyWith' isn't defined for the type 'InvoiceItem' • lib/screens/invoice_input_screen.dart:393:50 • undefined_method + info • 'activeColor' is deprecated and shouldn't be used. Use activeThumbColor instead. This feature was deprecated after v3.31.0-2.0.pre • lib/screens/invoice_input_screen.dart:600:13 • deprecated_member_use + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_input_screen.dart:619:51 • deprecated_member_use +warning • Unused import: 'package:path_provider/path_provider.dart' • lib/screens/management_screen.dart:6:8 • unused_import + info • Parameter 'key' could be a super parameter • lib/screens/management_screen.dart:16:9 • use_super_parameters + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/management_screen.dart:147:11 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/management_screen.dart:147:17 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/management_screen.dart:154:13 • deprecated_member_use + info • 'shareXFiles' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/management_screen.dart:154:19 • deprecated_member_use + info • Parameter 'key' could be a super parameter • lib/screens/product_master_screen.dart:8:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/product_master_screen.dart:182:55 • use_build_context_synchronously + info • The 'child' argument should be last in widget constructor invocations • lib/screens/product_master_screen.dart:199:9 • sort_child_properties_last + info • Parameter 'key' could be a super parameter • lib/screens/product_picker_modal.dart:11:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/sales_report_screen.dart:6:9 • use_super_parameters +warning • Unused import: 'package:crypto/crypto.dart' • lib/services/pdf_generator.dart:7:8 • unused_import + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:24 • unnecessary_brace_in_string_interps + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:63 • unnecessary_brace_in_string_interps + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:96 • unnecessary_brace_in_string_interps + info • Use the null-aware marker '?' rather than a null check via an 'if' • lib/services/pdf_generator.dart:346:13 • use_null_aware_elements + info • Parameter 'key' could be a super parameter • lib/widgets/slide_to_unlock.dart:8:9 • use_super_parameters -58 issues found. (ran in 23.0s) diff --git a/analyze_output_v2.txt b/analyze_output_v2.txt new file mode 100644 index 0000000..6971a27 --- /dev/null +++ b/analyze_output_v2.txt @@ -0,0 +1,76 @@ +Resolving dependencies... +Downloading packages... + geolocator 13.0.4 (14.0.2 available) + geolocator_android 4.6.2 (5.0.2 available) + image 4.5.4 (4.7.2 available) + meta 1.17.0 (1.18.1 available) + petitparser 7.0.1 (7.0.2 available) +Got dependencies! +5 packages have newer versions incompatible with dependency constraints. +Try `flutter pub outdated` for more information. +Analyzing gemi_invoice_backup2... + + info • Parameter 'key' could be a super parameter • lib/screens/activity_log_screen.dart:7:9 • use_super_parameters + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/activity_log_screen.dart:94:34 • deprecated_member_use + info • Parameter 'key' could be a super parameter • lib/screens/barcode_scanner_screen.dart:5:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/company_info_screen.dart:8:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/company_info_screen.dart:63:26 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/company_info_screen.dart:64:19 • use_build_context_synchronously + info • Parameter 'key' could be a super parameter • lib/screens/customer_master_screen.dart:7:9 • use_super_parameters + info • 'value' is deprecated and shouldn't be used. Use initialValue instead. This will set the initial value for the form field. This feature was deprecated after v3.33.0-1.0.pre • lib/screens/customer_master_screen.dart:60:19 • deprecated_member_use + info • The 'child' argument should be last in widget constructor invocations • lib/screens/customer_master_screen.dart:164:9 • sort_child_properties_last + info • Parameter 'key' could be a super parameter • lib/screens/customer_picker_modal.dart:11:9 • use_super_parameters + info • The private field _searchQuery could be 'final' • lib/screens/customer_picker_modal.dart:22:10 • prefer_final_fields +warning • The value of the field '_searchQuery' isn't used • lib/screens/customer_picker_modal.dart:22:10 • unused_field + info • The private field _allCustomers could be 'final' • lib/screens/customer_picker_modal.dart:23:18 • prefer_final_fields +warning • The value of the field '_allCustomers' isn't used • lib/screens/customer_picker_modal.dart:23:18 • unused_field + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:67:28 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:140:29 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/customer_picker_modal.dart:165:29 • use_build_context_synchronously + info • Parameter 'key' could be a super parameter • lib/screens/gps_history_screen.dart:6:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/invoice_detail_page.dart:20:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_detail_page.dart:137:28 • use_build_context_synchronously + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:145:5 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:145:11 • deprecated_member_use + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_detail_page.dart:161:9 • use_build_context_synchronously +warning • Dead code • lib/screens/invoice_detail_page.dart:171:47 • dead_code +warning • The left operand can't be null, so the right operand is never executed • lib/screens/invoice_detail_page.dart:171:50 • dead_null_aware_expression +warning • The left operand can't be null, so the right operand is never executed • lib/screens/invoice_detail_page.dart:172:58 • dead_null_aware_expression +warning • The '!' will have no effect because the receiver can't be null • lib/screens/invoice_detail_page.dart:181:65 • unnecessary_non_null_assertion +warning • The value of the local variable 'dateFormatter' isn't used • lib/screens/invoice_detail_page.dart:310:11 • unused_local_variable + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_detail_page.dart:349:114 • deprecated_member_use + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_detail_page.dart:379:84 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/invoice_detail_page.dart:617:13 • deprecated_member_use + info • 'shareXFiles' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/invoice_detail_page.dart:617:19 • deprecated_member_use +warning • The declaration '_SummaryRow' isn't referenced • lib/screens/invoice_detail_page.dart:664:7 • unused_element +warning • A value for optional parameter 'isBold' isn't ever given • lib/screens/invoice_detail_page.dart:667:51 • unused_element_parameter +warning • Unused import: '../models/customer_model.dart' • lib/screens/invoice_history_screen.dart:4:8 • unused_import + info • Parameter 'key' could be a super parameter • lib/screens/invoice_history_screen.dart:15:9 • use_super_parameters +warning • Unused import: 'package:uuid/uuid.dart' • lib/screens/invoice_input_screen.dart:2:8 • unused_import + info • Parameter 'key' could be a super parameter • lib/screens/invoice_input_screen.dart:20:9 • use_super_parameters +warning • The value of the field '_status' isn't used • lib/screens/invoice_input_screen.dart:41:10 • unused_field + info • The private field _signaturePath could be 'final' • lib/screens/invoice_input_screen.dart:44:17 • prefer_final_fields + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:137:30 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:141:28 • use_build_context_synchronously + info • Don't use 'BuildContext's across async gaps • lib/screens/invoice_input_screen.dart:142:21 • use_build_context_synchronously + error • The method 'copyWith' isn't defined for the type 'InvoiceItem' • lib/screens/invoice_input_screen.dart:393:50 • undefined_method + info • 'activeColor' is deprecated and shouldn't be used. Use activeThumbColor instead. This feature was deprecated after v3.31.0-2.0.pre • lib/screens/invoice_input_screen.dart:600:13 • deprecated_member_use + info • 'withOpacity' is deprecated and shouldn't be used. Use .withValues() to avoid precision loss • lib/screens/invoice_input_screen.dart:619:51 • deprecated_member_use +warning • Unused import: 'package:path_provider/path_provider.dart' • lib/screens/management_screen.dart:6:8 • unused_import + info • Parameter 'key' could be a super parameter • lib/screens/management_screen.dart:16:9 • use_super_parameters + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/management_screen.dart:147:11 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/management_screen.dart:147:17 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/management_screen.dart:154:13 • deprecated_member_use + info • 'shareXFiles' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/management_screen.dart:154:19 • deprecated_member_use + info • Parameter 'key' could be a super parameter • lib/screens/product_master_screen.dart:8:9 • use_super_parameters + info • Don't use 'BuildContext's across async gaps • lib/screens/product_master_screen.dart:182:55 • use_build_context_synchronously + info • The 'child' argument should be last in widget constructor invocations • lib/screens/product_master_screen.dart:199:9 • sort_child_properties_last + info • Parameter 'key' could be a super parameter • lib/screens/product_picker_modal.dart:11:9 • use_super_parameters + info • Parameter 'key' could be a super parameter • lib/screens/sales_report_screen.dart:6:9 • use_super_parameters +warning • Unused import: 'package:crypto/crypto.dart' • lib/services/pdf_generator.dart:7:8 • unused_import + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:24 • unnecessary_brace_in_string_interps + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:63 • unnecessary_brace_in_string_interps + info • Unnecessary braces in a string interpolation • lib/services/pdf_generator.dart:274:96 • unnecessary_brace_in_string_interps + info • Use the null-aware marker '?' rather than a null check via an 'if' • lib/services/pdf_generator.dart:346:13 • use_null_aware_elements + info • Parameter 'key' could be a super parameter • lib/widgets/slide_to_unlock.dart:8:9 • use_super_parameters + diff --git a/lib/models/company_model.dart b/lib/models/company_model.dart index ecd9bb9..a77620b 100644 --- a/lib/models/company_model.dart +++ b/lib/models/company_model.dart @@ -6,6 +6,7 @@ class CompanyInfo { final double defaultTaxRate; final String? sealPath; // 角印(印鑑)の画像パス final String taxDisplayMode; // 'normal', 'hidden', 'text_only' + final String? registrationNumber; // 追加: インボイス登録番号 (T番号) CompanyInfo({ required this.name, @@ -15,6 +16,7 @@ class CompanyInfo { this.defaultTaxRate = 0.10, this.sealPath, this.taxDisplayMode = 'normal', + this.registrationNumber, // 追加 }); Map toMap() { @@ -27,6 +29,7 @@ class CompanyInfo { 'default_tax_rate': defaultTaxRate, 'seal_path': sealPath, 'tax_display_mode': taxDisplayMode, + 'registration_number': registrationNumber, // 追加 }; } @@ -39,6 +42,7 @@ class CompanyInfo { defaultTaxRate: map['default_tax_rate'] ?? 0.10, sealPath: map['seal_path'], taxDisplayMode: map['tax_display_mode'] ?? 'normal', + registrationNumber: map['registration_number'], // 追加 ); } @@ -50,6 +54,7 @@ class CompanyInfo { double? defaultTaxRate, String? sealPath, String? taxDisplayMode, + String? registrationNumber, // 追加 }) { return CompanyInfo( name: name ?? this.name, @@ -59,6 +64,7 @@ class CompanyInfo { defaultTaxRate: defaultTaxRate ?? this.defaultTaxRate, sealPath: sealPath ?? this.sealPath, taxDisplayMode: taxDisplayMode ?? this.taxDisplayMode, + registrationNumber: registrationNumber ?? this.registrationNumber, // 追加 ); } } diff --git a/lib/models/invoice_models.dart b/lib/models/invoice_models.dart index 4587d57..f36afd3 100644 --- a/lib/models/invoice_models.dart +++ b/lib/models/invoice_models.dart @@ -40,6 +40,22 @@ class InvoiceItem { unitPrice: map['unit_price'], ); } + + InvoiceItem copyWith({ + String? id, // Added this to be complete + String? description, + int? quantity, + int? unitPrice, + String? productId, + }) { + return InvoiceItem( + id: id ?? this.id, // Added this to be complete + description: description ?? this.description, + quantity: quantity ?? this.quantity, + unitPrice: unitPrice ?? this.unitPrice, + productId: productId ?? this.productId, + ); + } } enum DocumentType { diff --git a/lib/screens/invoice_detail_page.dart b/lib/screens/invoice_detail_page.dart index ff384f3..65c497e 100644 --- a/lib/screens/invoice_detail_page.dart +++ b/lib/screens/invoice_detail_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'invoice_input_screen.dart'; // Add this line import 'package:intl/intl.dart'; import 'package:share_plus/share_plus.dart'; import 'package:open_filex/open_filex.dart'; @@ -220,7 +221,29 @@ class _InvoiceDetailPageState extends State { if (!_isEditing) ...[ IconButton(icon: const Icon(Icons.grid_on), onPressed: _exportCsv, tooltip: "CSV出力"), if (widget.isUnlocked) - IconButton(icon: const Icon(Icons.edit), onPressed: () => setState(() => _isEditing = true)), + IconButton( + icon: const Icon(Icons.edit_note), // アイコン変更 + tooltip: "詳細編集", + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InvoiceInputForm( + onInvoiceGenerated: (inv, path) { + // 保存完了時のコールバック(必要なら) + }, + existingInvoice: _currentInvoice, + ), + ), + ); + // 戻ってきたらデータを再読み込み(リポジトリから取得) + final repo = InvoiceRepository(); + final customerRepo = CustomerRepository(); + final customers = await customerRepo.getAllCustomers(); + final updated = (await repo.getAllInvoices(customers)).firstWhere((i) => i.id == _currentInvoice.id, orElse: () => _currentInvoice); + setState(() => _currentInvoice = updated); + }, + ), ] else ...[ if (isDraft) TextButton.icon( @@ -430,12 +453,14 @@ class _InvoiceDetailPageState extends State { return Column( children: [ _buildSummaryRow("小計", formatter.format(subtotal), textColor), - if (_companyInfo?.taxDisplayMode == 'normal') - _buildSummaryRow("消費税 (${(currentTaxRate * 100).toInt()}%)", formatter.format(tax), textColor), - if (_companyInfo?.taxDisplayMode == 'text_only') - _buildSummaryRow("消費税", "(税別)", textColor), + if (currentTaxRate > 0) ...[ + if (_companyInfo?.taxDisplayMode == 'normal') + _buildSummaryRow("消費税 (${(currentTaxRate * 100).toInt()}%)", formatter.format(tax), textColor), + if (_companyInfo?.taxDisplayMode == 'text_only') + _buildSummaryRow("消費税", "(税別)", textColor), + ], const Divider(color: Colors.grey), - _buildSummaryRow("合計金額", "¥${formatter.format(total)}", textColor, isTotal: true), + _buildSummaryRow(currentTaxRate > 0 ? "合計金額 (税込)" : "合計金額", "¥${formatter.format(total)}", textColor, isTotal: true), ], ); } diff --git a/lib/screens/invoice_history_screen.dart b/lib/screens/invoice_history_screen.dart index e71b62e..788039c 100644 --- a/lib/screens/invoice_history_screen.dart +++ b/lib/screens/invoice_history_screen.dart @@ -99,6 +99,7 @@ class _InvoiceHistoryScreenState extends State { return Scaffold( appBar: AppBar( + leading: const BackButton(), // 常に表示 title: GestureDetector( onLongPress: () { Navigator.push( @@ -231,10 +232,13 @@ class _InvoiceHistoryScreenState extends State { ), body: Column( children: [ - SlideToUnlock( - isLocked: !_isUnlocked, - onUnlocked: _toggleUnlock, - text: "スライドでロック解除", + Padding( + padding: const EdgeInsets.all(16.0), + child: SlideToUnlock( + isLocked: !_isUnlocked, + onUnlocked: _toggleUnlock, + text: "スライドでロック解除", + ), ), Expanded( child: _isLoading @@ -251,6 +255,7 @@ class _InvoiceHistoryScreenState extends State { ), ) : ListView.builder( + padding: const EdgeInsets.only(bottom: 100), // キーボードやFAB考慮 itemCount: _filteredInvoices.length, itemBuilder: (context, index) { final invoice = _filteredInvoices[index]; diff --git a/lib/screens/invoice_input_screen.dart b/lib/screens/invoice_input_screen.dart index 865a5b6..dc92ae5 100644 --- a/lib/screens/invoice_input_screen.dart +++ b/lib/screens/invoice_input_screen.dart @@ -15,10 +15,12 @@ import '../services/company_repository.dart'; class InvoiceInputForm extends StatefulWidget { final Function(Invoice invoice, String filePath) onInvoiceGenerated; + final Invoice? existingInvoice; // 追加: 編集時の既存伝票 const InvoiceInputForm({ Key? key, required this.onInvoiceGenerated, + this.existingInvoice, // 追加 }) : super(key: key); @override @@ -59,7 +61,20 @@ class _InvoiceInputFormState extends State { final companyInfo = await companyRepo.getCompanyInfo(); setState(() { _companyInfo = companyInfo; - _taxRate = companyInfo.defaultTaxRate; + // 既存伝票がある場合は初期値を上書き + if (widget.existingInvoice != null) { + final inv = widget.existingInvoice!; + _selectedCustomer = inv.customer; + _items.addAll(inv.items); + _taxRate = inv.taxRate; + _includeTax = inv.taxRate > 0; + _documentType = inv.documentType; + _selectedDate = inv.date; + _isDraft = inv.isDraft; + if (inv.subject != null) _subjectController.text = inv.subject!; + } else { + _taxRate = companyInfo.defaultTaxRate; + } }); } @@ -98,6 +113,7 @@ class _InvoiceInputFormState extends State { } final invoice = Invoice( + id: widget.existingInvoice?.id, // 既存IDがあれば引き継ぐ customer: _selectedCustomer!, date: _selectedDate, items: _items, @@ -180,7 +196,7 @@ class _InvoiceInputFormState extends State { backgroundColor: themeColor, appBar: AppBar( leading: const BackButton(), - title: Text(_isDraft ? "伝票作成 (下書きモード)" : "販売アシスト1号 V1.5.03"), + title: Text(_isDraft ? "伝票作成 (下書き)" : "販売アシスト1号 V1.5.04"), backgroundColor: _isDraft ? Colors.black87 : Colors.blueGrey, ), body: Column( @@ -298,7 +314,7 @@ class _InvoiceInputFormState extends State { leading: const Icon(Icons.business, color: Colors.blueGrey), title: Text(_selectedCustomer?.formalName ?? "取引先を選択してください", style: TextStyle(color: _selectedCustomer == null ? Colors.grey : Colors.black87, fontWeight: FontWeight.bold)), - subtitle: const Text("請求先マスターから選択"), + subtitle: const Text("顧客マスターから選択"), // 修正 trailing: const Icon(Icons.chevron_right), onTap: () async { await showModalBottomSheet( @@ -352,6 +368,42 @@ class _InvoiceInputFormState extends State { ), ], ), + onTap: () { + // 簡易編集ダイアログ + final descCtrl = TextEditingController(text: item.description); + final qtyCtrl = TextEditingController(text: item.quantity.toString()); + final priceCtrl = TextEditingController(text: item.unitPrice.toString()); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("明細の編集"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField(controller: descCtrl, decoration: const InputDecoration(labelText: "品名 / 項目")), + TextField(controller: qtyCtrl, decoration: const InputDecoration(labelText: "数量"), keyboardType: TextInputType.number), + TextField(controller: priceCtrl, decoration: const InputDecoration(labelText: "単価"), keyboardType: TextInputType.number), + ], + ), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: const Text("キャンセル")), + ElevatedButton( + onPressed: () { + setState(() { + _items[idx] = item.copyWith( + description: descCtrl.text, + quantity: int.tryParse(qtyCtrl.text) ?? item.quantity, + unitPrice: int.tryParse(priceCtrl.text) ?? item.unitPrice, + ); + }); + Navigator.pop(context); + }, + child: const Text("更新"), + ), + ], + ), + ); + }, ), ); }), @@ -370,18 +422,21 @@ class _InvoiceInputFormState extends State { const SizedBox(height: 8), Row( children: [ - const Text("消費税: "), - ChoiceChip( - label: const Text("10%"), - selected: _taxRate == 0.10, - onSelected: (val) => setState(() => _taxRate = 0.10), - ), - const SizedBox(width: 8), - ChoiceChip( - label: const Text("8%"), - selected: _taxRate == 0.08, - onSelected: (val) => setState(() => _taxRate = 0.08), - ), + if (_includeTax) ...[ + const Text("消費税: "), + ChoiceChip( + label: const Text("10%"), + selected: _taxRate == 0.10, + onSelected: (val) => setState(() => _taxRate = 0.10), + ), + const SizedBox(width: 8), + ChoiceChip( + label: const Text("8%"), + selected: _taxRate == 0.08, + onSelected: (val) => setState(() => _taxRate = 0.08), + ), + ] else + const Text("(税別設定のため設定なし)", style: TextStyle(color: Colors.grey)), const Spacer(), Switch( value: _includeTax, @@ -401,13 +456,15 @@ class _InvoiceInputFormState extends State { decoration: BoxDecoration(color: Colors.indigo.shade900, borderRadius: BorderRadius.circular(12)), child: Column( children: [ - _buildSummaryRow("小計 (税抜)", "¥${fmt.format(_subTotal)}", Colors.white70), - if (_companyInfo?.taxDisplayMode == 'normal') - _buildSummaryRow("消費税 (${(_taxRate * 100).toInt()}%)", "¥${fmt.format(_tax)}", Colors.white70), - if (_companyInfo?.taxDisplayMode == 'text_only') - _buildSummaryRow("消費税", "(税別)", Colors.white70), + _buildSummaryRow(_includeTax ? "小計 (税抜)" : "小計", "¥${fmt.format(_subTotal)}", Colors.white70), + if (_includeTax) ...[ + if (_companyInfo?.taxDisplayMode == 'normal') + _buildSummaryRow("消費税 (${(_taxRate * 100).toInt()}%)", "¥${fmt.format(_tax)}", Colors.white70), + if (_companyInfo?.taxDisplayMode == 'text_only') + _buildSummaryRow("消費税", "(税別)", Colors.white70), + ], const Divider(color: Colors.white24), - _buildSummaryRow("合計金額", "¥${fmt.format(_total)}", Colors.white, fontSize: 24), + _buildSummaryRow(_includeTax ? "合計金額 (税込)" : "合計金額", "¥${fmt.format(_total)}", Colors.white, fontSize: 24), ], ), ); @@ -479,8 +536,8 @@ class _InvoiceInputFormState extends State { Expanded( child: OutlinedButton.icon( onPressed: _showPreview, - icon: const Icon(Icons.remove_red_eye), - label: const Text("仮表示"), + icon: const Icon(Icons.picture_as_pdf), // アイコン変更 + label: const Text("PDFプレビュー"), // 名称変更 style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), side: const BorderSide(color: Colors.indigo), @@ -521,7 +578,31 @@ class _InvoiceInputFormState extends State { } Widget _buildDraftToggle() { - // ... (existing code omitted for brevity but I'll provide the new method below it) + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: _isDraft ? Colors.black26 : Colors.orange.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: _isDraft ? Colors.orangeAccent : Colors.orange, width: 2), + ), + child: Row( + children: [ + Icon(_isDraft ? Icons.drafts : Icons.check_circle, color: Colors.orange), + const SizedBox(width: 12), + Expanded( + child: Text( + _isDraft ? "下書き (保存のみ・PDF未生成)" : "正式発行 (PDF生成)", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: _isDraft ? Colors.white70 : Colors.orange.shade900), + ), + ), + Switch( + value: _isDraft, + activeColor: Colors.orangeAccent, + onChanged: (val) => setState(() => _isDraft = val), + ), + ], + ), + ); } Widget _buildSubjectSection(Color textColor) { diff --git a/lib/services/database_helper.dart b/lib/services/database_helper.dart index f2246e9..e9ec4fe 100644 --- a/lib/services/database_helper.dart +++ b/lib/services/database_helper.dart @@ -2,7 +2,7 @@ import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; class DatabaseHelper { - static const _databaseVersion = 12; + static const _databaseVersion = 13; static final DatabaseHelper _instance = DatabaseHelper._internal(); static Database? _database; @@ -94,6 +94,9 @@ class DatabaseHelper { if (oldVersion < 12) { await db.execute('ALTER TABLE invoices ADD COLUMN subject TEXT'); } + if (oldVersion < 13) { + await db.execute('ALTER TABLE company_info ADD COLUMN registration_number TEXT'); + } } Future _onCreate(Database db, int version) async { @@ -193,7 +196,8 @@ class DatabaseHelper { tel TEXT, default_tax_rate REAL DEFAULT 0.10, seal_path TEXT, - tax_display_mode TEXT DEFAULT "normal" + tax_display_mode TEXT DEFAULT "normal", + registration_number TEXT ) '''); diff --git a/lib/services/pdf_generator.dart b/lib/services/pdf_generator.dart index 2c55293..3f05474 100644 --- a/lib/services/pdf_generator.dart +++ b/lib/services/pdf_generator.dart @@ -96,6 +96,8 @@ Future buildInvoiceDocument(Invoice invoice) async { if (companyInfo.zipCode != null) pw.Text("〒${companyInfo.zipCode}"), if (companyInfo.address != null) pw.Text(companyInfo.address!), if (companyInfo.tel != null) pw.Text("TEL: ${companyInfo.tel}"), + if (companyInfo.registrationNumber != null && companyInfo.registrationNumber!.isNotEmpty) + pw.Text("登録番号: ${companyInfo.registrationNumber!}", style: const pw.TextStyle(fontSize: 10)), ], ), if (sealImage != null) @@ -256,7 +258,20 @@ Future generateInvoicePdf(Invoice invoice) async { final String subjectStr = invoice.subject?.isNotEmpty == true ? "_${invoice.subject}" : ""; // {日付}({タイプ}){顧客名}_{案件}_{金額}_{HASH下8桁}.pdf - String fileName = "${dateStr}(${invoice.documentTypeName})${invoice.customerNameForDisplay}${subjectStr}_${amountStr}円_$hash.pdf"; + // 顧客名から敬称を除去 + String safeCustomerName = invoice.customerNameForDisplay + .replaceAll('株式会社', '') + .replaceAll('(株)', '') + .replaceAll('(株)', '') + .replaceAll('有限会社', '') + .replaceAll('(有)', '') + .replaceAll('(有)', '') + .replaceAll('合同会社', '') + .replaceAll('(同)', '') + .replaceAll('(同)', '') + .trim(); + + String fileName = "${dateStr}(${invoice.documentTypeName})${safeCustomerName}${subjectStr}_${amountStr}円_$hash.pdf"; final directory = await getExternalStorageDirectory(); if (directory == null) return null; diff --git a/目標.md b/目標.md index 04af8cb..d8f12c3 100644 --- a/目標.md +++ b/目標.md @@ -56,4 +56,23 @@ 20260214(請求書)佐々木製作所_10,000円_12345678.pdf 明細欄にはmarkdown的要素が使える様に、簡単なものが欲しい。  インデントや箇条書き、太字など。問題はodooとの連携と型番。 ++ 編集画面にタイトルが2行出るようになった ++ 配色でバックと文字が同系色になり見えなくなる事がある ++ 「仮表示」は「PDFプレビュー」に名称変更 ++ PDFに自社情報が反映されない T番号が有る場合はT番号をPDFに記載する ++ 一覧表示する時はキーボードに隠れる部分があるのでその分余白を表示する ++ 一覧表示・検索の時にも左上には戻る矢印が必須 ++ 値引きも商品とするか悩んでいます ++ 税別の場合は編集画面に消費税項目編集部分は表示しない ++ 合計金額部分も税別の時は表示を専用に切り替える ++ 仮表示(PDFプレビューに改名)は何度でも実行可能にする ++ 伝票入力画面で行の編集が可能にする ++ 顧客マスター呼び出しボタンが請求先マスターになっているのを修正 ++ アンロックのスライドの右端が画面外にはみ出している ++ 編集したのを保存すると沢山伝票が増え続ける ++ 商品マスターにはグルーピング機能を追加する(商品を選択すると芋蔓式にインデントした商品が引用される) ++ 顧客マスターにはメールアドレスが必要(PDFを送信するから) ++ ファイル名には株式会社や有限会社は除去して社名だけを引用する ++ 伝票を新規発行する時は顧客名から引用できる伝票を表示し選択して引用する機能を実装する +