feat: add historical data
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
@@ -10,6 +11,7 @@ import '../models/closed_tab.dart';
|
||||
import '../models/closed_tab_item.dart';
|
||||
import '../models/payment_method.dart';
|
||||
import '../models/product.dart';
|
||||
import '../models/tab_event.dart';
|
||||
import '../models/tab_item.dart';
|
||||
import '../models/tab_item_purchase.dart';
|
||||
|
||||
@@ -69,11 +71,13 @@ abstract class BarTabService {
|
||||
/// The tab itself stays open under the same customer name.
|
||||
///
|
||||
/// Throws [TabVersionConflictException] when [expectedVersion] is given and
|
||||
/// the tab changed since.
|
||||
/// the tab changed since. [commandId] is the remote command that requested
|
||||
/// the settlement, if any.
|
||||
Future<void> closeTab(
|
||||
String tabId, {
|
||||
PaymentMethod paymentMethod = PaymentMethod.cash,
|
||||
int? expectedVersion,
|
||||
String? commandId,
|
||||
});
|
||||
|
||||
Future<List<ClosedTab>> getClosedTabs();
|
||||
@@ -91,9 +95,11 @@ abstract class BarTabService {
|
||||
|
||||
class DriftBarTabService implements BarTabService {
|
||||
final AppDatabase database;
|
||||
final TabEventFactory eventFactory;
|
||||
final _uuid = const Uuid();
|
||||
|
||||
DriftBarTabService({required this.database});
|
||||
DriftBarTabService({required this.database, TabEventFactory? eventFactory})
|
||||
: eventFactory = eventFactory ?? TabEventFactory();
|
||||
|
||||
TabItemPurchase _mapPurchaseRow(TabItemPurchaseRow row) {
|
||||
return TabItemPurchase(
|
||||
@@ -255,6 +261,21 @@ class DriftBarTabService implements BarTabService {
|
||||
)..where((item) => item.tabId.equals(tabId))).go();
|
||||
}
|
||||
|
||||
/// Queues [event] in the outbox. Call it inside the transaction that makes
|
||||
/// the change, so the change and its event are stored together or not at
|
||||
/// all.
|
||||
Future<void> _recordEvent(TabEvent event) async {
|
||||
await database
|
||||
.into(database.tabEvents)
|
||||
.insert(
|
||||
TabEventsCompanion.insert(
|
||||
id: event.id,
|
||||
payload: jsonEncode(event.payload),
|
||||
createdAt: DateTime.now(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _incrementTabVersion(String tabId) async {
|
||||
await (database.update(
|
||||
database.barTabs,
|
||||
@@ -341,6 +362,15 @@ class DriftBarTabService implements BarTabService {
|
||||
|
||||
for (final item in tab.items) {
|
||||
await database.increaseStock(item.productId, item.quantity);
|
||||
await _recordEvent(
|
||||
eventFactory.lineRemoved(
|
||||
tabId: tab.id,
|
||||
customerName: tab.customerName,
|
||||
productName: item.productName,
|
||||
unitPriceInCents: item.unitPriceInCents,
|
||||
quantity: item.quantity,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await _deleteItemsOfTab(tabId);
|
||||
@@ -356,6 +386,9 @@ class DriftBarTabService implements BarTabService {
|
||||
required Product product,
|
||||
}) async {
|
||||
await database.transaction(() async {
|
||||
final tabRow = await _getTabRow(tabId);
|
||||
if (tabRow == null) throw TabNotFoundException(tabId);
|
||||
|
||||
await database.decreaseStock(product.id, 1);
|
||||
|
||||
final existingItem =
|
||||
@@ -373,6 +406,16 @@ class DriftBarTabService implements BarTabService {
|
||||
TabItemsCompanion(quantity: Value(existingItem.quantity + 1)),
|
||||
);
|
||||
await _recordPurchase(existingItem.id);
|
||||
// The line keeps the price it was first added at
|
||||
await _recordEvent(
|
||||
eventFactory.lineAdded(
|
||||
tabId: tabId,
|
||||
customerName: tabRow.customerName,
|
||||
productName: existingItem.productName,
|
||||
unitPriceInCents: existingItem.unitPriceInCents,
|
||||
quantity: 1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final tabItemId = _uuid.v4();
|
||||
|
||||
@@ -390,6 +433,15 @@ class DriftBarTabService implements BarTabService {
|
||||
),
|
||||
);
|
||||
await _recordPurchase(tabItemId);
|
||||
await _recordEvent(
|
||||
eventFactory.lineAdded(
|
||||
tabId: tabId,
|
||||
customerName: tabRow.customerName,
|
||||
productName: product.name,
|
||||
unitPriceInCents: product.priceInCents,
|
||||
quantity: 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await _incrementTabVersion(tabId);
|
||||
@@ -429,6 +481,20 @@ class DriftBarTabService implements BarTabService {
|
||||
..where((row) => row.id.equals(tabItemId)))
|
||||
.write(TabItemsCompanion(quantity: Value(newQuantity)));
|
||||
|
||||
final tabRow = await _getTabRow(item.tabId);
|
||||
final lineEvent = actualDelta > 0
|
||||
? eventFactory.lineAdded
|
||||
: eventFactory.lineRemoved;
|
||||
await _recordEvent(
|
||||
lineEvent(
|
||||
tabId: item.tabId,
|
||||
customerName: tabRow?.customerName ?? '',
|
||||
productName: item.productName,
|
||||
unitPriceInCents: item.unitPriceInCents,
|
||||
quantity: actualDelta.abs(),
|
||||
),
|
||||
);
|
||||
|
||||
await _incrementTabVersion(item.tabId);
|
||||
|
||||
return actualDelta;
|
||||
@@ -440,6 +506,7 @@ class DriftBarTabService implements BarTabService {
|
||||
String tabId, {
|
||||
PaymentMethod paymentMethod = PaymentMethod.cash,
|
||||
int? expectedVersion,
|
||||
String? commandId,
|
||||
}) async {
|
||||
await database.transaction(() async {
|
||||
final tabRow = await _getTabRow(tabId);
|
||||
@@ -488,6 +555,34 @@ class DriftBarTabService implements BarTabService {
|
||||
]);
|
||||
});
|
||||
|
||||
// One settlement, not a removal per line: these drinks were sold
|
||||
final settledItems = [
|
||||
for (final item in items)
|
||||
if (item.quantity > 0) item,
|
||||
];
|
||||
if (settledItems.isNotEmpty) {
|
||||
await _recordEvent(
|
||||
eventFactory.settled(
|
||||
tabId: tabId,
|
||||
customerName: tabRow.customerName,
|
||||
amountInCents: settledItems.fold(
|
||||
0,
|
||||
(total, item) => total + item.lineTotalInCents,
|
||||
),
|
||||
paymentMethod: paymentMethod,
|
||||
commandId: commandId,
|
||||
items: [
|
||||
for (final item in settledItems)
|
||||
(
|
||||
productName: item.productName,
|
||||
quantity: item.quantity,
|
||||
unitPriceInCents: item.unitPriceInCents,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await _deleteItemsOfTab(tabId);
|
||||
await _incrementTabVersion(tabId);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user