211 lines
6.3 KiB
Dart
211 lines
6.3 KiB
Dart
import 'package:collection/collection.dart';
|
|
|
|
/// 受注ステータスの定義。
|
|
enum SalesOrderStatus {
|
|
draft,
|
|
confirmed,
|
|
picking,
|
|
shipped,
|
|
closed,
|
|
cancelled,
|
|
}
|
|
|
|
extension SalesOrderStatusX on SalesOrderStatus {
|
|
String get displayName {
|
|
switch (this) {
|
|
case SalesOrderStatus.draft:
|
|
return '下書き';
|
|
case SalesOrderStatus.confirmed:
|
|
return '確定';
|
|
case SalesOrderStatus.picking:
|
|
return '出荷準備中';
|
|
case SalesOrderStatus.shipped:
|
|
return '出荷済み';
|
|
case SalesOrderStatus.closed:
|
|
return '完了';
|
|
case SalesOrderStatus.cancelled:
|
|
return 'キャンセル';
|
|
}
|
|
}
|
|
|
|
static SalesOrderStatus fromDbValue(String? value) {
|
|
return SalesOrderStatus.values.firstWhere(
|
|
(status) => status.name == value,
|
|
orElse: () => SalesOrderStatus.draft,
|
|
);
|
|
}
|
|
}
|
|
|
|
class SalesOrderItem {
|
|
SalesOrderItem({
|
|
required this.id,
|
|
required this.orderId,
|
|
required this.description,
|
|
required this.quantity,
|
|
required this.unitPrice,
|
|
this.productId,
|
|
this.taxRate = 0,
|
|
this.sortIndex = 0,
|
|
});
|
|
|
|
final String id;
|
|
final String orderId;
|
|
final String? productId;
|
|
final String description;
|
|
final int quantity;
|
|
final int unitPrice;
|
|
final double taxRate;
|
|
final int sortIndex;
|
|
|
|
int get lineTotal => quantity * unitPrice;
|
|
|
|
Map<String, dynamic> toMap() => {
|
|
'id': id,
|
|
'order_id': orderId,
|
|
'product_id': productId,
|
|
'description': description,
|
|
'quantity': quantity,
|
|
'unit_price': unitPrice,
|
|
'tax_rate': taxRate,
|
|
'sort_index': sortIndex,
|
|
};
|
|
|
|
factory SalesOrderItem.fromMap(Map<String, dynamic> map) => SalesOrderItem(
|
|
id: map['id'] as String,
|
|
orderId: map['order_id'] as String,
|
|
productId: map['product_id'] as String?,
|
|
description: map['description'] as String,
|
|
quantity: map['quantity'] as int,
|
|
unitPrice: map['unit_price'] as int,
|
|
taxRate: (map['tax_rate'] as num?)?.toDouble() ?? 0,
|
|
sortIndex: map['sort_index'] as int? ?? 0,
|
|
);
|
|
}
|
|
|
|
class SalesOrder {
|
|
SalesOrder({
|
|
required this.id,
|
|
required this.customerId,
|
|
required this.orderDate,
|
|
required this.status,
|
|
required this.subtotal,
|
|
required this.taxAmount,
|
|
required this.totalAmount,
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
this.orderNumber,
|
|
this.customerNameSnapshot,
|
|
this.requestedShipDate,
|
|
this.notes,
|
|
this.assignedTo,
|
|
this.workflowStage,
|
|
this.items = const [],
|
|
});
|
|
|
|
final String id;
|
|
final String customerId;
|
|
final String? customerNameSnapshot;
|
|
final DateTime orderDate;
|
|
final DateTime? requestedShipDate;
|
|
final SalesOrderStatus status;
|
|
final int subtotal;
|
|
final int taxAmount;
|
|
final int totalAmount;
|
|
final String? orderNumber;
|
|
final String? notes;
|
|
final String? assignedTo;
|
|
final String? workflowStage;
|
|
final DateTime createdAt;
|
|
final DateTime updatedAt;
|
|
final List<SalesOrderItem> items;
|
|
|
|
SalesOrder copyWith({
|
|
String? id,
|
|
String? customerId,
|
|
String? customerNameSnapshot,
|
|
DateTime? orderDate,
|
|
DateTime? requestedShipDate,
|
|
SalesOrderStatus? status,
|
|
int? subtotal,
|
|
int? taxAmount,
|
|
int? totalAmount,
|
|
String? orderNumber,
|
|
String? notes,
|
|
String? assignedTo,
|
|
String? workflowStage,
|
|
DateTime? createdAt,
|
|
DateTime? updatedAt,
|
|
List<SalesOrderItem>? items,
|
|
}) {
|
|
return SalesOrder(
|
|
id: id ?? this.id,
|
|
customerId: customerId ?? this.customerId,
|
|
customerNameSnapshot: customerNameSnapshot ?? this.customerNameSnapshot,
|
|
orderDate: orderDate ?? this.orderDate,
|
|
requestedShipDate: requestedShipDate ?? this.requestedShipDate,
|
|
status: status ?? this.status,
|
|
subtotal: subtotal ?? this.subtotal,
|
|
taxAmount: taxAmount ?? this.taxAmount,
|
|
totalAmount: totalAmount ?? this.totalAmount,
|
|
orderNumber: orderNumber ?? this.orderNumber,
|
|
notes: notes ?? this.notes,
|
|
assignedTo: assignedTo ?? this.assignedTo,
|
|
workflowStage: workflowStage ?? this.workflowStage,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
updatedAt: updatedAt ?? this.updatedAt,
|
|
items: items ?? this.items,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toMap() => {
|
|
'id': id,
|
|
'order_number': orderNumber,
|
|
'customer_id': customerId,
|
|
'customer_name_snapshot': customerNameSnapshot,
|
|
'order_date': orderDate.toIso8601String(),
|
|
'requested_ship_date': requestedShipDate?.toIso8601String(),
|
|
'status': status.name,
|
|
'subtotal': subtotal,
|
|
'tax_amount': taxAmount,
|
|
'total_amount': totalAmount,
|
|
'notes': notes,
|
|
'assigned_to': assignedTo,
|
|
'workflow_stage': workflowStage,
|
|
'created_at': createdAt.toIso8601String(),
|
|
'updated_at': updatedAt.toIso8601String(),
|
|
};
|
|
|
|
factory SalesOrder.fromMap(Map<String, dynamic> map, {List<SalesOrderItem> items = const []}) {
|
|
return SalesOrder(
|
|
id: map['id'] as String,
|
|
orderNumber: map['order_number'] as String?,
|
|
customerId: map['customer_id'] as String,
|
|
customerNameSnapshot: map['customer_name_snapshot'] as String?,
|
|
orderDate: DateTime.parse(map['order_date'] as String),
|
|
requestedShipDate: (map['requested_ship_date'] as String?) != null
|
|
? DateTime.parse(map['requested_ship_date'] as String)
|
|
: null,
|
|
status: SalesOrderStatusX.fromDbValue(map['status'] as String?),
|
|
subtotal: map['subtotal'] as int? ?? 0,
|
|
taxAmount: map['tax_amount'] as int? ?? 0,
|
|
totalAmount: map['total_amount'] as int? ?? 0,
|
|
notes: map['notes'] as String?,
|
|
assignedTo: map['assigned_to'] as String?,
|
|
workflowStage: map['workflow_stage'] as String?,
|
|
createdAt: DateTime.parse(map['created_at'] as String),
|
|
updatedAt: DateTime.parse(map['updated_at'] as String),
|
|
items: items,
|
|
);
|
|
}
|
|
|
|
SalesOrder recalculateTotals({double? defaultTaxRate}) {
|
|
final newSubtotal = items.fold<int>(0, (sum, item) => sum + item.lineTotal);
|
|
final taxRate = defaultTaxRate ?? items.map((e) => e.taxRate).firstWhereOrNull((rate) => rate > 0) ?? 0;
|
|
final newTaxAmount = (newSubtotal * taxRate).round();
|
|
return copyWith(
|
|
subtotal: newSubtotal,
|
|
taxAmount: newTaxAmount,
|
|
totalAmount: newSubtotal + newTaxAmount,
|
|
);
|
|
}
|
|
}
|