feat: implement save receipt functionality with transaction handling and DTOs
Test Suite / test (24.15.0) (push) Has been cancelled

This commit is contained in:
Nils-Johan Gynther
2026-05-09 15:04:23 +02:00
parent 853e853e5e
commit 8354abbc8f
10 changed files with 461 additions and 99 deletions
@@ -255,6 +255,64 @@ class ImportRepository {
}
}
/// Save receipt items in a single atomic transaction.
///
/// This endpoint handles:
/// - Creating/validating products
/// - Creating/merging inventory items
/// - Adding to pantry
/// - Learning aliases
/// - Learning unit mappings
Future<Map<String, dynamic>> saveReceipt({
required List<Map<String, dynamic>> items,
bool isAdminLearning = false,
String? token,
}) async {
try {
developer.log('Starting saveReceipt with ${items.length} items', name: 'ImportRepository');
final uri = Uri.parse('$_baseUrl/receipt-import/save');
final response = await _client.post(
uri,
headers: {
'Content-Type': 'application/json',
if (token != null) 'Authorization': 'Bearer $token',
},
body: jsonEncode({
'items': items,
if (isAdminLearning) 'isAdminLearning': true,
}),
).timeout(
const Duration(seconds: 60),
onTimeout: () {
developer.log('saveReceipt request timed out', name: 'ImportRepository', error: 'Timeout');
throw ApiException(
type: ApiErrorType.network,
message: 'Sparandet tok för lång tid. Försök igen.',
);
},
);
developer.log('saveReceipt response status: ${response.statusCode}', name: 'ImportRepository');
if (response.statusCode < 200 || response.statusCode >= 300) {
developer.log('saveReceipt error: ${response.body}', name: 'ImportRepository', error: 'HTTP Error');
throw ApiException(
type: _mapStatusCodeToErrorType(response.statusCode),
message: 'Fel vid sparande: ${response.body}',
statusCode: response.statusCode,
);
}
final result = _parseResponse(response) as Map<String, dynamic>;
developer.log('saveReceipt succeeded: ${result['created']} created, ${result['merged']} merged', name: 'ImportRepository');
return result;
} catch (e) {
developer.log('Exception during saveReceipt: $e', name: 'ImportRepository', error: e);
rethrow;
}
}
/// Helper method to map HTTP status codes to [ApiErrorType].
ApiErrorType _mapStatusCodeToErrorType(int statusCode) {
if (statusCode == 401) return ApiErrorType.unauthorized;