/// A parsed receipt row shown on the review screen. library; import 'receipt_bounds.dart'; class LineItem { LineItem({ required this.id, required this.name, required this.price, this.quantity, this.unitPrice, this.discount = 0, this.sourceBounds, this.needsManualReview = false, }); final String id; final String name; /// Line total after any discount. final double price; final int? quantity; final double? unitPrice; /// Negative amount when a discount was folded into [price]. final double discount; /// Region on the receipt photo (normalized 0–1) used when parsing this line. final ReceiptBounds? sourceBounds; /// True when the parser could not confidently resolve price/qty for this line. final bool needsManualReview; bool get hasDiscount => discount != 0; /// List price before a folded discount. Equals [price] when there is none. double get originalPrice { if (!hasDiscount) return price; return ((price - discount) * 100).round() / 100; } LineItem copyWith({ String? id, String? name, double? price, int? quantity, double? unitPrice, double? discount, ReceiptBounds? sourceBounds, bool? needsManualReview, bool clearQuantity = false, bool clearSourceBounds = false, }) { return LineItem( id: id ?? this.id, name: name ?? this.name, price: price ?? this.price, quantity: clearQuantity ? null : (quantity ?? this.quantity), unitPrice: clearQuantity ? null : (unitPrice ?? this.unitPrice), discount: discount ?? this.discount, sourceBounds: clearSourceBounds ? null : (sourceBounds ?? this.sourceBounds), needsManualReview: needsManualReview ?? this.needsManualReview, ); } }