Files
nearle_pos/lib/domain/repositories/sync_repository.dart
2026-07-29 13:06:39 +05:30

80 lines
2.0 KiB
Dart

import '../entities/shift_report.dart';
import '../entities/sync_event.dart';
import '../entities/transaction.dart';
/// Result of one end-of-day upload.
class SyncOutcome {
const SyncOutcome({
required this.attempted,
required this.uploaded,
this.error,
});
final int attempted;
final int uploaded;
final String? error;
bool get isSuccess => error == null;
bool get hadNothingToDo => attempted == 0;
int get remaining => attempted - uploaded;
}
/// One row of the order sync log.
class OrderSyncRow {
const OrderSyncRow({
required this.orderId,
required this.invoiceNumber,
required this.total,
required this.createdAt,
required this.isSynced,
this.syncedAt,
this.attempts = 0,
this.error,
});
final String orderId;
final String invoiceNumber;
final double total;
final DateTime createdAt;
final bool isSynced;
final DateTime? syncedAt;
final int attempts;
final String? error;
}
/// The terminal's two network touchpoints.
///
/// Morning: pull the catalogue. End of day: upload every order still at
/// `sync_status = 0`. Nothing else leaves the device.
abstract class SyncRepository {
bool get hasCatalogue;
DateTime? get lastImportAt;
String? get catalogueRevision;
/// Morning step — downloads products and writes them to SQLite.
Future<SyncEvent> importCatalogue({
void Function(double progress, String stage)? onProgress,
});
/// How many bills are still held locally.
Future<int> unsyncedCount();
Future<List<SaleTransaction>> unsyncedOrders();
/// Today's trading totals, read back from SQLite.
Future<ShiftReport> todayReport({
required String terminalId,
required String cashierName,
});
/// End-of-day step — uploads pending orders and flips the accepted ones to
/// `sync_status = 1`. Failures leave every row untouched at 0.
Future<SyncOutcome> syncOrders({
void Function(double progress, String stage)? onProgress,
});
Future<List<OrderSyncRow>> orderSyncRows({int limit = 200});
List<SyncEvent> get events;
}