135 lines
No EOL
4 KiB
Dart
135 lines
No EOL
4 KiB
Dart
// Version: 1.5 - Estimate モデル定義(見積書)
|
||
import '../services/database_helper.dart';
|
||
|
||
/// 見積項目クラス
|
||
class EstimateItem {
|
||
int productId;
|
||
String productName;
|
||
double unitPrice;
|
||
int quantity;
|
||
|
||
EstimateItem({
|
||
required this.productId,
|
||
required this.productName,
|
||
required this.unitPrice,
|
||
this.quantity = 1,
|
||
});
|
||
|
||
/// 小計金額(税込)を取得
|
||
double get subtotal => unitPrice * quantity;
|
||
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'productId': productId,
|
||
'productName': productName,
|
||
'unitPrice': unitPrice,
|
||
'quantity': quantity,
|
||
'subtotal': subtotal,
|
||
};
|
||
}
|
||
|
||
factory EstimateItem.fromMap(Map<dynamic, dynamic> map) {
|
||
return EstimateItem(
|
||
productId: map['productId'] as int,
|
||
productName: map['productName'] as String,
|
||
unitPrice: (map['unitPrice'] as num).toDouble(),
|
||
quantity: map['quantity'] as int? ?? 1,
|
||
);
|
||
}
|
||
|
||
static List<EstimateItem> fromMaps(List<dynamic> maps) {
|
||
return maps.map((e) => EstimateItem.fromMap(e as Map)).toList();
|
||
}
|
||
}
|
||
|
||
/// 見積書モデル
|
||
class Estimate {
|
||
int? id;
|
||
String customerCode; // データベースでは product_code として保存(顧客コード)
|
||
String estimateNumber;
|
||
DateTime? expiryDate;
|
||
double totalAmount;
|
||
double taxRate;
|
||
DateTime createdAt;
|
||
DateTime updatedAt;
|
||
List<EstimateItem> items = [];
|
||
|
||
Estimate({
|
||
this.id,
|
||
required this.customerCode,
|
||
required this.estimateNumber,
|
||
this.expiryDate,
|
||
this.totalAmount = 0,
|
||
this.taxRate = 8.0, // デフォルト:8%
|
||
DateTime? createdAt,
|
||
DateTime? updatedAt,
|
||
List<EstimateItem>? items,
|
||
}) : createdAt = createdAt ?? DateTime.now(),
|
||
updatedAt = updatedAt ?? DateTime.now(),
|
||
items = items ?? [];
|
||
|
||
/// マップから Estimate オブジェクトへ変換
|
||
factory Estimate.fromMap(Map<String, dynamic> map) {
|
||
return Estimate(
|
||
id: map['id'] as int?,
|
||
customerCode: map['customer_code'] as String, // 'product_code' を 'customer_code' として扱う
|
||
estimateNumber: map['estimate_number'] as String,
|
||
expiryDate: map['expiry_date'] != null ? DateTime.parse(map['expiry_date']) : null,
|
||
totalAmount: (map['total_amount'] as num).toDouble(),
|
||
taxRate: (map['tax_rate'] as num?)?.toDouble() ?? 8.0, // 税率(%):デフォルト 8%
|
||
createdAt: DateTime.parse(map['created_at']),
|
||
updatedAt: DateTime.parse(map['updated_at']),
|
||
);
|
||
}
|
||
|
||
/// Map に変換
|
||
Map<String, dynamic> toMap() {
|
||
return {
|
||
'id': id,
|
||
'customer_code': customerCode,
|
||
'estimate_number': estimateNumber,
|
||
'expiry_date': expiryDate?.toIso8601String(),
|
||
'total_amount': totalAmount,
|
||
'tax_rate': taxRate,
|
||
'created_at': createdAt.toIso8601String(),
|
||
'updated_at': updatedAt.toIso8601String(),
|
||
};
|
||
}
|
||
|
||
/// カピービルダ
|
||
Estimate copyWith({
|
||
int? id,
|
||
String? customerCode,
|
||
String? estimateNumber,
|
||
DateTime? expiryDate,
|
||
double? totalAmount,
|
||
int? taxRate,
|
||
DateTime? createdAt,
|
||
DateTime? updatedAt,
|
||
List<EstimateItem>? items,
|
||
}) {
|
||
return Estimate(
|
||
id: id ?? this.id,
|
||
customerCode: customerCode ?? this.customerCode,
|
||
estimateNumber: estimateNumber ?? this.estimateNumber,
|
||
expiryDate: expiryDate ?? this.expiryDate,
|
||
totalAmount: totalAmount ?? this.totalAmount,
|
||
taxRate: (taxRate as num?)?.toDouble() ?? this.taxRate, // 型エラー修正
|
||
createdAt: createdAt ?? this.createdAt,
|
||
updatedAt: updatedAt ?? this.updatedAt,
|
||
items: items ?? this.items,
|
||
);
|
||
}
|
||
|
||
/// 合計金額を再計算(items から集計)
|
||
void recalculate() {
|
||
totalAmount = items.fold(0, (sum, item) => sum + item.subtotal);
|
||
}
|
||
|
||
/// 見積書番号を生成(YYYYMM-NNNN 形式)
|
||
static String generateEstimateNumber() {
|
||
final now = DateTime.now();
|
||
final yearMonth = '${now.year}${now.month.toString().padLeft(2, '0')}';
|
||
return '$yearMonth-${DateTime.now().millisecondsSinceEpoch.toString().substring(6, 10)}';
|
||
}
|
||
} |