67 lines
1.7 KiB
Dart
67 lines
1.7 KiB
Dart
/// 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,
|
||
);
|
||
}
|
||
}
|