added product import and billing integration
This commit is contained in:
@@ -11,10 +11,13 @@ import 'catalogue_wire.dart';
|
||||
/// Pulls the catalogue from the back office over HTTP.
|
||||
///
|
||||
/// ```
|
||||
/// GET {base}/catalogue?since={revision}&page={n}
|
||||
/// GET {base}/catalogue?since={revision}&page={n}&page_size={pageSize}&store_id={storeId}
|
||||
/// Authorization: Bearer {apiKey}
|
||||
/// ```
|
||||
///
|
||||
/// Pages are 0-indexed — the first page requested is `page=0` — matching the
|
||||
/// back office's own convention rather than the more common 1-indexed one.
|
||||
///
|
||||
/// ```json
|
||||
/// {
|
||||
/// "revision": "rev-8821",
|
||||
@@ -53,6 +56,10 @@ class HttpCatalogueSource implements CatalogueSource {
|
||||
/// connection.
|
||||
static const int maxPages = 200;
|
||||
|
||||
/// Rows requested per page. Sent as `page_size` on every request so the
|
||||
/// back office doesn't fall back to its own (smaller) default.
|
||||
static const int pageSize = 500;
|
||||
|
||||
static const Duration _timeout = Duration(seconds: 30);
|
||||
|
||||
@override
|
||||
@@ -77,7 +84,7 @@ class HttpCatalogueSource implements CatalogueSource {
|
||||
|
||||
var revision = since ?? '';
|
||||
var isDelta = false;
|
||||
var page = 1;
|
||||
var page = 0;
|
||||
|
||||
onProgress?.call(0.05, 'Contacting the back office…');
|
||||
|
||||
@@ -137,6 +144,7 @@ class HttpCatalogueSource implements CatalogueSource {
|
||||
queryParameters: {
|
||||
if (since != null && since.isNotEmpty) 'since': since,
|
||||
'page': '$page',
|
||||
'page_size': '$pageSize',
|
||||
'store_id': config.storeId,
|
||||
'terminal_id': config.terminalId,
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../core/config/sync_config.dart';
|
||||
import 'order_transport.dart';
|
||||
@@ -13,6 +14,12 @@ import 'order_transport.dart';
|
||||
/// having as the route to bring up first, and as the fallback when a broker is
|
||||
/// unreachable but the internet is not.
|
||||
///
|
||||
/// ```
|
||||
/// POST {base}/orders
|
||||
/// { "schema": 1, "batch_id": "…", "store_id": "…", "terminal_id": "…",
|
||||
/// "orders": [ … ] }
|
||||
/// ```
|
||||
///
|
||||
/// The endpoint must answer with the ids it committed:
|
||||
///
|
||||
/// ```json
|
||||
@@ -29,6 +36,8 @@ class HttpOrderTransport implements OrderTransport {
|
||||
final SyncConfig config;
|
||||
final http.Client _client;
|
||||
|
||||
static const _uuid = Uuid();
|
||||
|
||||
final _connection = StreamController<bool>.broadcast();
|
||||
|
||||
bool _reachable = true;
|
||||
@@ -73,6 +82,16 @@ class HttpOrderTransport implements OrderTransport {
|
||||
|
||||
final uri = Uri.parse('${config.httpBaseUrl}/$path');
|
||||
|
||||
// Deterministic from the set of ids in this batch — not a fresh random
|
||||
// id per attempt — so a retry after a timeout (the same rows, because
|
||||
// nothing was marked sent) carries the exact same batch_id as the
|
||||
// attempt that may already have landed. That is what lets the back
|
||||
// office collapse a retried batch server-side instead of re-billing it.
|
||||
final batchId = _uuid.v5(
|
||||
Uuid.NAMESPACE_URL,
|
||||
items.map((o) => o['id']).join('|'),
|
||||
);
|
||||
|
||||
http.Response response;
|
||||
try {
|
||||
response = await _client
|
||||
@@ -82,15 +101,13 @@ class HttpOrderTransport implements OrderTransport {
|
||||
'content-type': 'application/json',
|
||||
if (config.apiKey != null)
|
||||
'authorization': 'Bearer ${config.apiKey}',
|
||||
// Lets the endpoint collapse a retried batch server-side rather
|
||||
// than relying on every order id being checked individually.
|
||||
'idempotency-key': _batchKey(items),
|
||||
'idempotency-key': batchId,
|
||||
},
|
||||
body: jsonEncode({
|
||||
'schema': 1,
|
||||
'batch_id': batchId,
|
||||
'store_id': config.storeId,
|
||||
'terminal_id': config.terminalId,
|
||||
'sent_at': DateTime.now().toIso8601String(),
|
||||
key: items,
|
||||
}),
|
||||
)
|
||||
@@ -143,11 +160,6 @@ class HttpOrderTransport implements OrderTransport {
|
||||
return PushReceipt(accepted: accepted, rejected: rejected);
|
||||
}
|
||||
|
||||
/// Stable for a given set of records, so a retry after a timeout carries the
|
||||
/// same key as the attempt that may already have landed.
|
||||
String _batchKey(List<Map<String, Object?>> items) =>
|
||||
items.map((o) => o['id']).join('|').hashCode.toRadixString(16);
|
||||
|
||||
void _setReachable(bool value) {
|
||||
if (_reachable == value) return;
|
||||
_reachable = value;
|
||||
|
||||
Reference in New Issue
Block a user