barcode_scanner/lib/backend/api/api_calls.dart
your-name 68a2803b6e enhance: Enhances product scanning with local ObjectBox integration
Moves product lookup from external API calls to a local ObjectBox database. This improves performance and enables offline product identification during scanning.

Removes the standalone scanner page, consolidating barcode scanning functionality directly into the reception flow for a more streamlined user experience.

Updates ObjectBox entity fields by removing `final` modifiers, allowing the database to manage and update persisted data effectively. Introduces new methods in the reception scan model to support local product checks, retrieval, and quantity increment for scanned items.
2025-07-30 19:01:14 +03:00

326 lines
11 KiB
Dart

import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:e_scan/backend/objectbox/objectbox_manager.dart';
import 'package:e_scan/backend/schema/auth/auth_model.dart';
import 'package:e_scan/backend/schema/stock_picking/stock_picking_model.dart';
import 'package:e_scan/backend/schema/stock_picking/stock_picking_record_model.dart';
import 'package:e_scan/provider_container.dart';
import 'package:e_scan/services/dio_service.dart';
import 'package:e_scan/services/token_provider.dart';
import 'package:e_scan/utils/utils.dart';
import 'package:flutter/foundation.dart';
import 'package:multiple_result/multiple_result.dart';
class ApiCalls {
static DioService dioService = DioService(
tokenProvider: providerContainer.read(tokenProvider),
);
static Future<Result<AuthModel, Error>> signIn({
required String email,
required String password,
}) async {
try {
final response = await dioService.post(
path: '/simpos/v1/sign_in',
data: {
"params": {
"login": email,
"password": password,
"db": "bitnami_odoo",
},
},
);
if (response.statusCode == 200) {
final data = response.data;
if (data['result']['success'] == true) {
String? cookie;
if (response.headers.map.containsKey('set-cookie')) {
cookie = response.headers.map['set-cookie']?.firstOrNull;
}
final auth = AuthModel.fromJson(
data['result']['data'],
).copyWith(sessionId: cookie);
return Result.success(auth);
} else {
return Result.error(Error(data['result']['success']));
}
} else {
debugPrint('Erreur réseau: ${response.statusCode}');
return Result.error(Error(response.statusMessage));
}
} catch (e) {
debugPrint('Erreur lors de la requête: $e');
return Result.error(Error(e));
}
}
static Future<Result<List<StockPickingRecordEntity>, Error>>
getAllStockPiking() async {
try {
final stockPickingRecords = objectboxManager.store
.box<StockPickingRecordEntity>();
if (!(await checkInternetConnexion())) {
// return local data
return Result.success(stockPickingRecords.getAll());
}
final response = await dioService.post(
path: '/web/dataset/call_kw/stock.picking/web_search_read',
data: {
//"id": 23,
//"jsonrpc": "2.0",
//"method": "call",
"params": {
"model": "stock.picking",
"method": "web_search_read",
"args": [],
"kwargs": {
"specification": {
"company_id": {"fields": {}},
"priority": {},
"name": {},
"partner_id": {
"fields": {"display_name": {}},
},
"location_dest_id": {
"fields": {"complete_name": {}},
},
"location_id": {
"fields": {"complete_name": {}},
},
"user_id": {
"fields": {"display_name": {}},
},
"scheduled_date": {},
"picking_type_code": {},
"products_availability_state": {},
"products_availability": {},
"date_deadline": {},
"date_done": {},
"origin": {},
"backorder_id": {
"fields": {"display_name": {}},
},
"picking_type_id": {
"fields": {"display_name": {}},
},
"state": {},
"activity_exception_decoration": {},
"activity_exception_icon": {},
"json_popover": {},
"move_line_ids_without_package": {
"fields": {
"product_id": {
"fields": {"display_name": {}, "barcode": {}},
},
"quantity": {}, // quantité
},
},
"move_ids_without_package": {
"fields": {
"product_id": {
"fields": {"display_name": {}, "barcode": {}},
},
"quantity": {}, // quantité
"product_uom_qty": {}, //quantité demandé
},
"context": {
"form_view_ref": "stock.view_stock_move_operations",
},
"limit": 40,
"order": "",
},
},
"offset": 0,
"order": "",
"limit": 80,
"context": {
"lang": "en_US",
"tz": "Africa/Nairobi",
"uid": 2,
"allowed_company_ids": [1],
"bin_size": true,
"active_model": "stock.picking.type",
"active_id": 2,
"active_ids": [2],
"contact_display": "partner_address",
"default_picking_type_id": 2,
"default_company_id": 1,
"current_company_id": 1,
},
"count_limit": 10001,
"domain": [
["picking_type_code", "=", "incoming"],
],
},
},
},
);
if (response.statusCode == 200) {
final data = response.data;
if (data.containsKey('result')) {
final result = StockPickingResponseModel.fromJson(data);
final recordsModel =
result.result?.records ?? <StockPickingRecordModel>[];
// add data to local
final records = recordsModel.map((e) => e.toEntity()).toList();
return Result.success(records);
} else {
return Result.error(Error(data['error']));
}
} else {
debugPrint('Erreur réseau: ${response.statusCode}');
return Result.error(Error(response.statusMessage));
}
} catch (e) {
debugPrint('Erreur lors de la requête: $e');
return Result.error(Error(e));
}
}
static Future<Result<StockPickingRecordEntity, Error>> getStockPikingById({
required int id,
}) async {
try {
final stockPickingRecords = objectboxManager.store
.box<StockPickingRecordEntity>();
if (!(await checkInternetConnexion())) {
// return local data
final entity = stockPickingRecords.get(id);
if (entity == null) return Result.error(Error('Not found'));
return Result.success(entity);
}
final response = await dioService.post(
path: '/web/dataset/call_kw/stock.picking/web_read',
data: {
"params": {
"model": "stock.picking",
"method": "web_read",
"args": [
[id],
],
"kwargs": {
"context": {
"lang": "en_US",
"tz": "Africa/Nairobi",
"uid": 2,
"allowed_company_ids": [1],
"bin_size": true,
"active_model": "stock.picking.type",
"active_id": 2,
"active_ids": [2],
"contact_display": "partner_address",
"default_picking_type_id": 2,
"default_company_id": 1,
},
"specification": {
"state": {},
"return_count": {},
"priority": {},
"picking_type_code": {},
"name": {},
"partner_id": {
"fields": {"display_name": {}},
},
"picking_type_id": {
"fields": {"display_name": {}},
},
"location_id": {
"fields": {"complete_name": {}},
},
"location_dest_id": {
"fields": {"complete_name": {}},
},
"backorder_id": {
"fields": {"display_name": {}},
},
"use_create_lots": {},
"scheduled_date": {},
"json_popover": {},
"date_deadline": {},
"products_availability_state": {},
"products_availability": {},
"date_done": {},
"origin": {},
"picking_properties": {},
"move_line_ids_without_package": {
"fields": {
"product_id": {
"fields": {"display_name": {}, "barcode": {}},
},
"quantity": {}, // quantité
},
},
"move_ids_without_package": {
"fields": {
"product_id": {
"fields": {"display_name": {}, "barcode": {}},
},
"quantity": {}, // quantité
"product_uom_qty": {}, //quantité demandé
},
"context": {
"form_view_ref": "stock.view_stock_move_operations",
},
"limit": 40,
"order": "",
},
"id": {},
"package_level_ids": {
"fields": {
"is_fresh_package": {},
"company_id": {"fields": {}},
"package_id": {
"fields": {"display_name": {}},
},
"state": {}, //done, ready, waiting,
"is_done": {},
},
"limit": 40,
"order": "",
},
"move_type": {},
"user_id": {
"fields": {"display_name": {}},
},
"sale_id": {
"fields": {"display_name": {}},
},
"note": {},
"show_check_availability": {},
"has_scrap_move": {},
"has_packages": {},
"is_locked": {},
"show_next_pickings": {},
"company_id": {"fields": {}},
"picking_type_entire_packs": {},
"display_name": {},
},
},
},
},
);
if (response.statusCode == 200) {
final data = response.data;
if (data.containsKey('result')) {
final datas = data['result'] as List;
if (datas.isNotEmpty) {
final recordModel = StockPickingRecordModel.fromJson(datas.first);
final entity = recordModel.toEntity();
return Result.success(entity);
} else {
return Result.error(Error('Data not found'));
}
} else {
return Result.error(Error(data['error']));
}
} else {
debugPrint('Erreur réseau: ${response.statusCode}');
return Result.error(Error(response.statusMessage));
}
} catch (e) {
debugPrint('Erreur lors de la requête: $e');
return Result.error(Error(e));
}
}
}