
Updates the `createBackorderConfirmation` API call to dynamically specify whether to create a backorder (reliquat) or not. Introduces a `toBackorder` parameter, enabling the API to handle both "with backorder" and "without backorder" scenarios based on user selection. This centralizes the backorder status setting within a single API call. Additionally, adds loading indicators to the backorder dialog buttons for improved user feedback during the confirmation process.
563 lines
18 KiB
Dart
563 lines
18 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/backend/schema/stock_picking/update_move_line_dto.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 as Map<String, dynamic>;
|
|
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 as Map<String, dynamic>;
|
|
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));
|
|
}
|
|
}
|
|
|
|
static Future<bool> updateAllMoveLineOnStockPicking({
|
|
required int stockPickingId,
|
|
required List<UpdateMoveLineDto> moveLineDto,
|
|
}) async {
|
|
try {
|
|
final response = await dioService.post(
|
|
path: '/web/dataset/call_kw/stock.picking/write',
|
|
data: {
|
|
"jsonrpc": "2.0",
|
|
"method": "call",
|
|
"params": {
|
|
"model": "stock.picking",
|
|
"method": "write",
|
|
"args": [
|
|
[
|
|
stockPickingId, //id stock piking
|
|
],
|
|
{
|
|
"move_line_ids": [...moveLineDto.map((e) => e.toList())],
|
|
},
|
|
],
|
|
"kwargs": {"context": {}},
|
|
},
|
|
},
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = response.data as Map<String, dynamic>;
|
|
if (data.containsKey('result')) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
debugPrint('Erreur réseau: ${response.statusCode}');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de la requête: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Future<bool> validateStockPicking({
|
|
required int stockPickingId,
|
|
}) async {
|
|
try {
|
|
final response = await dioService.post(
|
|
path: '/web/dataset/call_kw/stock.picking/button_validate',
|
|
data: {
|
|
"jsonrpc": "2.0",
|
|
"method": "call",
|
|
"params": {
|
|
"model": "stock.picking",
|
|
"method": "button_validate",
|
|
"args": [
|
|
[stockPickingId],
|
|
],
|
|
"kwargs": {"context": {}},
|
|
},
|
|
},
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = response.data as Map<String, dynamic>;
|
|
if (data.containsKey('result')) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
debugPrint('Erreur réseau: ${response.statusCode}');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de la requête: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// If the requested quantity of the product to be received is greater than
|
|
/// the quantity actually received,
|
|
/// a confirmation popup must be displayed.
|
|
/// The user will then need to perform two actions:
|
|
/// choose whether or not to create a backorder.
|
|
/// Therefore, this function must be called to generate this confirmation.
|
|
/// This function returns the `ID of the backorder` confirmation popup,
|
|
/// which must be used to perform the next action,
|
|
/// either `withBackorder()` or `withoutBackorder()`.
|
|
static Future<int?> createBackorderConfirmation({
|
|
required int stockPickingId,
|
|
required bool toBackorder,
|
|
}) async {
|
|
try {
|
|
final response = await dioService.post(
|
|
path: '/web/dataset/call_kw/stock.backorder.confirmation/create',
|
|
data: {
|
|
"jsonrpc": "2.0",
|
|
"method": "call",
|
|
"params": {
|
|
"model": "stock.backorder.confirmation",
|
|
"method": "create",
|
|
"args": [
|
|
{
|
|
"pick_ids": [
|
|
[
|
|
6,
|
|
0,
|
|
[
|
|
stockPickingId, // stock picking id
|
|
],
|
|
],
|
|
],
|
|
"backorder_confirmation_line_ids": [
|
|
[
|
|
0,
|
|
0,
|
|
{
|
|
"picking_id": stockPickingId, // stock picking id
|
|
"to_backorder":
|
|
toBackorder, // true = avec reliquat / false = sans reliquat
|
|
},
|
|
],
|
|
],
|
|
},
|
|
],
|
|
"kwargs": {},
|
|
},
|
|
},
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = response.data as Map<String, dynamic>;
|
|
if (data.containsKey('result')) {
|
|
return data['result'];
|
|
} else {
|
|
return null;
|
|
}
|
|
} else {
|
|
debugPrint('Erreur réseau: ${response.statusCode}');
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de la requête: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<bool> withBackorder({
|
|
required int stockPickingId,
|
|
required int createBackorderConfirmationId,
|
|
}) async {
|
|
try {
|
|
final response = await dioService.post(
|
|
path: '/web/dataset/call_kw/stock.backorder.confirmation/process',
|
|
data: {
|
|
"jsonrpc": "2.0",
|
|
"method": "call",
|
|
"params": {
|
|
"model": "stock.backorder.confirmation",
|
|
"method": "process",
|
|
"args": [
|
|
[
|
|
createBackorderConfirmationId, // id popup backorder confirmation reponse -> create popup reliquat
|
|
],
|
|
],
|
|
"kwargs": {
|
|
"context": {
|
|
"button_validate_picking_ids": [
|
|
stockPickingId, // picking id]
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = response.data as Map<String, dynamic>;
|
|
if (data.containsKey('result')) {
|
|
return data['result'];
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
debugPrint('Erreur réseau: ${response.statusCode}');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de la requête: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Future<bool> withoutBackorder({
|
|
required int stockPickingId,
|
|
required int createBackorderConfirmationId,
|
|
}) async {
|
|
try {
|
|
final response = await dioService.post(
|
|
path:
|
|
'/web/dataset/call_kw/stock.backorder.confirmation/process_cancel_backorder',
|
|
data: {
|
|
"jsonrpc": "2.0",
|
|
"method": "call",
|
|
"params": {
|
|
"model": "stock.backorder.confirmation",
|
|
"method": "process_cancel_backorder",
|
|
"args": [
|
|
[
|
|
createBackorderConfirmationId, // id popup backorder confirmation reponse -> create popup reliquat
|
|
],
|
|
],
|
|
"kwargs": {
|
|
"context": {
|
|
"button_validate_picking_ids": [
|
|
stockPickingId, // stock picking id
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
);
|
|
if (response.statusCode == 200) {
|
|
final data = response.data as Map<String, dynamic>;
|
|
if (data.containsKey('result')) {
|
|
return data['result'];
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
debugPrint('Erreur réseau: ${response.statusCode}');
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Erreur lors de la requête: $e');
|
|
return false;
|
|
}
|
|
}
|
|
}
|