payfrit-app/lib/models/cart.dart
John Mizerek f505eeb722 Implement complete cart management system
Add full cart functionality with API integration:
- Created Cart and OrderLineItem models with robust JSON parsing
- Implemented cart API methods (getOrCreateCart, setLineItem, getCart, submitOrder)
- Added cart state management to AppState with item count tracking
- Built cart view screen with item display, quantity editing, and removal
- Added cart badge to menu screen showing item count
- Implemented real add-to-cart logic with recursive modifier handling
- Added category name display in menu browsing
- Fixed API response case sensitivity (ORDER/ORDERLINEITEMS)
- Enhanced MenuItem model with categoryName field

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 11:14:19 -08:00

202 lines
6 KiB
Dart

class Cart {
final int orderId;
final String orderUuid;
final int userId;
final int businessId;
final double businessDeliveryMultiplier;
final int orderTypeId;
final double deliveryFee;
final int statusId;
final int? addressId;
final int? paymentId;
final String? remarks;
final DateTime addedOn;
final DateTime lastEditedOn;
final DateTime? submittedOn;
final int servicePointId;
final List<OrderLineItem> lineItems;
const Cart({
required this.orderId,
required this.orderUuid,
required this.userId,
required this.businessId,
required this.businessDeliveryMultiplier,
required this.orderTypeId,
required this.deliveryFee,
required this.statusId,
this.addressId,
this.paymentId,
this.remarks,
required this.addedOn,
required this.lastEditedOn,
this.submittedOn,
required this.servicePointId,
required this.lineItems,
});
factory Cart.fromJson(Map<String, dynamic> json) {
final order = (json["ORDER"] ?? json["Order"]) as Map<String, dynamic>? ?? {};
final lineItemsJson = (json["ORDERLINEITEMS"] ?? json["OrderLineItems"]) as List? ?? [];
return Cart(
orderId: _parseInt(order["OrderID"]) ?? 0,
orderUuid: (order["OrderUUID"] as String?) ?? "",
userId: _parseInt(order["OrderUserID"]) ?? 0,
businessId: _parseInt(order["OrderBusinessID"]) ?? 0,
businessDeliveryMultiplier: _parseDouble(order["OrderBusinessDeliveryMultiplier"]) ?? 0.0,
orderTypeId: _parseInt(order["OrderTypeID"]) ?? 0,
deliveryFee: _parseDouble(order["OrderDeliveryFee"]) ?? 0.0,
statusId: _parseInt(order["OrderStatusID"]) ?? 0,
addressId: _parseInt(order["OrderAddressID"]),
paymentId: _parseInt(order["OrderPaymentID"]),
remarks: order["OrderRemarks"] as String?,
addedOn: _parseDateTime(order["OrderAddedOn"]),
lastEditedOn: _parseDateTime(order["OrderLastEditedOn"]),
submittedOn: _parseDateTime(order["OrderSubmittedOn"]),
servicePointId: _parseInt(order["OrderServicePointID"]) ?? 0,
lineItems: lineItemsJson
.map((item) => OrderLineItem.fromJson(item as Map<String, dynamic>))
.toList(),
);
}
static int? _parseInt(dynamic value) {
if (value == null) return null;
if (value is int) return value;
if (value is num) return value.toInt();
if (value is String) {
if (value.isEmpty) return null;
return int.tryParse(value);
}
return null;
}
static double? _parseDouble(dynamic value) {
if (value == null) return null;
if (value is double) return value;
if (value is num) return value.toDouble();
if (value is String) {
if (value.isEmpty) return null;
return double.tryParse(value);
}
return null;
}
static DateTime _parseDateTime(dynamic value) {
if (value == null) return DateTime.now();
if (value is DateTime) return value;
if (value is String) {
try {
return DateTime.parse(value);
} catch (e) {
return DateTime.now();
}
}
return DateTime.now();
}
double get subtotal {
return lineItems
.where((item) => !item.isDeleted && item.parentOrderLineItemId == 0)
.fold(0.0, (sum, item) => sum + (item.price * item.quantity));
}
double get total => subtotal + deliveryFee;
int get itemCount {
return lineItems
.where((item) => !item.isDeleted && item.parentOrderLineItemId == 0)
.fold(0, (sum, item) => sum + item.quantity);
}
}
class OrderLineItem {
final int orderLineItemId;
final int parentOrderLineItemId;
final int orderId;
final int itemId;
final int statusId;
final double price;
final int quantity;
final String? remark;
final bool isDeleted;
final DateTime addedOn;
const OrderLineItem({
required this.orderLineItemId,
required this.parentOrderLineItemId,
required this.orderId,
required this.itemId,
required this.statusId,
required this.price,
required this.quantity,
this.remark,
required this.isDeleted,
required this.addedOn,
});
factory OrderLineItem.fromJson(Map<String, dynamic> json) {
return OrderLineItem(
orderLineItemId: _parseInt(json["OrderLineItemID"]) ?? 0,
parentOrderLineItemId: _parseInt(json["OrderLineItemParentOrderLineItemID"]) ?? 0,
orderId: _parseInt(json["OrderLineItemOrderID"]) ?? 0,
itemId: _parseInt(json["OrderLineItemItemID"]) ?? 0,
statusId: _parseInt(json["OrderLineItemStatusID"]) ?? 0,
price: _parseDouble(json["OrderLineItemPrice"]) ?? 0.0,
quantity: _parseInt(json["OrderLineItemQuantity"]) ?? 0,
remark: json["OrderLineItemRemark"] as String?,
isDeleted: _parseBool(json["OrderLineItemIsDeleted"]),
addedOn: _parseDateTime(json["OrderLineItemAddedOn"]),
);
}
static int? _parseInt(dynamic value) {
if (value == null) return null;
if (value is int) return value;
if (value is num) return value.toInt();
if (value is String) {
if (value.isEmpty) return null;
return int.tryParse(value);
}
return null;
}
static double? _parseDouble(dynamic value) {
if (value == null) return null;
if (value is double) return value;
if (value is num) return value.toDouble();
if (value is String) {
if (value.isEmpty) return null;
return double.tryParse(value);
}
return null;
}
static bool _parseBool(dynamic value) {
if (value == null) return false;
if (value is bool) return value;
if (value is num) return value != 0;
if (value is String) {
final lower = value.toLowerCase();
return lower == "true" || lower == "1";
}
return false;
}
static DateTime _parseDateTime(dynamic value) {
if (value == null) return DateTime.now();
if (value is DateTime) return value;
if (value is String) {
try {
return DateTime.parse(value);
} catch (e) {
return DateTime.now();
}
}
return DateTime.now();
}
bool get isRootItem => parentOrderLineItemId == 0;
bool get isModifier => parentOrderLineItemId != 0;
}