feat: make server owner of tabs
This commit is contained in:
@@ -4,18 +4,33 @@ import 'payment_method.dart';
|
||||
|
||||
/// Types of [TabEvent] the server understands.
|
||||
enum TabEventType {
|
||||
tabOpened('tab_opened'),
|
||||
tabRenamed('tab_renamed'),
|
||||
tabDeleted('tab_deleted'),
|
||||
lineAdded('line_added'),
|
||||
lineRemoved('line_removed'),
|
||||
settled('settled');
|
||||
settled('settled'),
|
||||
|
||||
/// A stock count or tracking change made on the tablet. Not about a tab:
|
||||
/// it has no `tabId`.
|
||||
stockSet('stock_set');
|
||||
|
||||
final String value;
|
||||
|
||||
const TabEventType(this.value);
|
||||
|
||||
static TabEventType? fromValue(String value) {
|
||||
for (final type in TabEventType.values) {
|
||||
if (type.value == value) return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that happened on a tab, reported to the server for sales
|
||||
/// statistics. [payload] is the JSON object that is stored in the outbox and
|
||||
/// sent as is.
|
||||
/// Something that happened on a tab. Together the events form the operation
|
||||
/// log the server builds the venue's tabs from, and the tablet replays the
|
||||
/// ones the server hasn't applied yet on top of the server's tabs. [payload]
|
||||
/// is the JSON object that is stored in the outbox and sent as is.
|
||||
class TabEvent {
|
||||
final String id;
|
||||
final Map<String, dynamic> payload;
|
||||
@@ -25,6 +40,7 @@ class TabEvent {
|
||||
|
||||
/// One settled line in a `settled` event.
|
||||
typedef SettledLine = ({
|
||||
String productId,
|
||||
String productName,
|
||||
int quantity,
|
||||
int unitPriceInCents,
|
||||
@@ -37,10 +53,46 @@ class TabEventFactory {
|
||||
|
||||
TabEventFactory({DateTime Function()? now}) : _now = now ?? DateTime.now;
|
||||
|
||||
/// [quantity] is how many pieces were added; always positive.
|
||||
TabEvent tabOpened({
|
||||
required String tabId,
|
||||
required String customerName,
|
||||
required DateTime openedAt,
|
||||
}) {
|
||||
return _event(
|
||||
TabEventType.tabOpened,
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
fields: {'openedAt': openedAt.toUtc().toIso8601String()},
|
||||
);
|
||||
}
|
||||
|
||||
/// [customerName] is the new name.
|
||||
TabEvent tabRenamed({required String tabId, required String customerName}) {
|
||||
return _event(
|
||||
TabEventType.tabRenamed,
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
fields: const {},
|
||||
);
|
||||
}
|
||||
|
||||
/// Written after a `line_removed` for every line still on the tab.
|
||||
TabEvent tabDeleted({required String tabId, required String customerName}) {
|
||||
return _event(
|
||||
TabEventType.tabDeleted,
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
fields: const {},
|
||||
);
|
||||
}
|
||||
|
||||
/// [quantity] is how many pieces were added; always positive. [lineId] is
|
||||
/// the local line, so the server can keep its id.
|
||||
TabEvent lineAdded({
|
||||
required String tabId,
|
||||
required String customerName,
|
||||
required String lineId,
|
||||
required String productId,
|
||||
required String productName,
|
||||
required int unitPriceInCents,
|
||||
required int quantity,
|
||||
@@ -49,6 +101,8 @@ class TabEventFactory {
|
||||
TabEventType.lineAdded,
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
lineId: lineId,
|
||||
productId: productId,
|
||||
productName: productName,
|
||||
unitPriceInCents: unitPriceInCents,
|
||||
quantity: quantity,
|
||||
@@ -59,6 +113,8 @@ class TabEventFactory {
|
||||
TabEvent lineRemoved({
|
||||
required String tabId,
|
||||
required String customerName,
|
||||
required String lineId,
|
||||
required String productId,
|
||||
required String productName,
|
||||
required int unitPriceInCents,
|
||||
required int quantity,
|
||||
@@ -67,6 +123,8 @@ class TabEventFactory {
|
||||
TabEventType.lineRemoved,
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
lineId: lineId,
|
||||
productId: productId,
|
||||
productName: productName,
|
||||
unitPriceInCents: unitPriceInCents,
|
||||
quantity: quantity,
|
||||
@@ -92,6 +150,7 @@ class TabEventFactory {
|
||||
'items': [
|
||||
for (final item in items)
|
||||
{
|
||||
'productId': item.productId,
|
||||
'productName': item.productName,
|
||||
'quantity': item.quantity,
|
||||
'unitPriceInCents': item.unitPriceInCents,
|
||||
@@ -101,6 +160,23 @@ class TabEventFactory {
|
||||
);
|
||||
}
|
||||
|
||||
/// The stock of [productId] was set to [quantity] on this tablet (a count,
|
||||
/// or a new product's starting stock); null stops tracking it.
|
||||
TabEvent stockSet({required String productId, required int? quantity}) {
|
||||
final id = _uuid.v4();
|
||||
|
||||
return TabEvent(
|
||||
id: id,
|
||||
payload: {
|
||||
'id': id,
|
||||
'type': TabEventType.stockSet.value,
|
||||
'productId': productId,
|
||||
'quantity': quantity,
|
||||
'occurredAt': _now().toUtc().toIso8601String(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// The server's payment method names: `cash`, `payconiq`,
|
||||
/// `payment_pending` or `other`.
|
||||
static String paymentMethodValue(PaymentMethod method) {
|
||||
@@ -115,6 +191,8 @@ class TabEventFactory {
|
||||
TabEventType type, {
|
||||
required String tabId,
|
||||
required String customerName,
|
||||
required String lineId,
|
||||
required String productId,
|
||||
required String productName,
|
||||
required int unitPriceInCents,
|
||||
required int quantity,
|
||||
@@ -128,6 +206,8 @@ class TabEventFactory {
|
||||
tabId: tabId,
|
||||
customerName: customerName,
|
||||
fields: {
|
||||
'lineId': lineId,
|
||||
'productId': productId,
|
||||
'productName': productName,
|
||||
'unitPriceInCents': unitPriceInCents,
|
||||
'quantity': quantity,
|
||||
|
||||
Reference in New Issue
Block a user