mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 13:36:50 +00:00
API post request now uses HttpClient
This commit is contained in:
parent
71340da068
commit
b8c535560d
100
lib/api.dart
100
lib/api.dart
@ -388,22 +388,96 @@ class InvenTreeAPI {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a POST request
|
/**
|
||||||
Future<http.Response> post(String url, {Map<String, dynamic> body}) async {
|
* Perform a HTTP POST request
|
||||||
|
* Returns a json object (or null if unsuccessful)
|
||||||
|
*/
|
||||||
|
Future<dynamic> post(String url, {Map<String, dynamic> body, int expectedStatusCode=201}) async {
|
||||||
var _url = makeApiUrl(url);
|
var _url = makeApiUrl(url);
|
||||||
var _headers = jsonHeaders();
|
var _headers = jsonHeaders();
|
||||||
|
|
||||||
print("POST: ${_url} -> ${body.toString()}");
|
print("POST: ${_url} -> ${body.toString()}");
|
||||||
|
|
||||||
var data = jsonEncode(body);
|
var client = createClient(true);
|
||||||
|
|
||||||
return http.post(_url,
|
HttpClientRequest request = await client.postUrl(Uri.parse(_url));
|
||||||
headers: _headers,
|
|
||||||
body: data,
|
var data = json.encode(body);
|
||||||
);
|
|
||||||
|
// Set headers
|
||||||
|
// Ref: https://stackoverflow.com/questions/59713003/body-not-sending-using-map-in-flutter
|
||||||
|
request.headers.set('Accept', 'application/json');
|
||||||
|
request.headers.set('Content-type', 'application/json');
|
||||||
|
request.headers.set('Content-Length', data.length.toString());
|
||||||
|
|
||||||
|
if (profile != null) {
|
||||||
|
request.headers.set(
|
||||||
|
HttpHeaders.authorizationHeader,
|
||||||
|
_authorizationHeader(profile.username, profile.password)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add JSON data to the request
|
||||||
|
request.add(utf8.encode(data));
|
||||||
|
|
||||||
|
HttpClientResponse response = await request.close()
|
||||||
|
.timeout(Duration(seconds: 30))
|
||||||
|
.catchError((error) {
|
||||||
|
print("POST request returned error");
|
||||||
|
print("URL: ${_url}");
|
||||||
|
print("Error: ${error.toString()}");
|
||||||
|
|
||||||
|
var ctx = OneContext().context;
|
||||||
|
|
||||||
|
if (error is SocketException) {
|
||||||
|
showServerError(
|
||||||
|
I18N.of(ctx).connectionRefused,
|
||||||
|
error.toString()
|
||||||
|
);
|
||||||
|
} else if (error is TimeoutException) {
|
||||||
|
showTimeoutError(ctx);
|
||||||
|
} else {
|
||||||
|
showServerError(
|
||||||
|
I18N.of(ctx).serverError,
|
||||||
|
error.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
|
print("null response from POST ${_url}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode != expectedStatusCode) {
|
||||||
|
showStatusCodeError(response.statusCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the body of the response to a JSON object
|
||||||
|
String responseData = await response.transform(utf8.decoder).join();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var data = json.decode(responseData);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
|
||||||
|
} on FormatException {
|
||||||
|
|
||||||
|
print("JSON format exception!");
|
||||||
|
print("${responseData}");
|
||||||
|
|
||||||
|
showServerError(
|
||||||
|
"Format Exception",
|
||||||
|
"JSON data format exception:\n${responseData}"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClient _client(bool allowBadCert) {
|
HttpClient createClient(bool allowBadCert) {
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
@ -433,7 +507,7 @@ class InvenTreeAPI {
|
|||||||
* Perform a HTTP GET request
|
* Perform a HTTP GET request
|
||||||
* Returns a json object (or null if did not complete)
|
* Returns a json object (or null if did not complete)
|
||||||
*/
|
*/
|
||||||
Future<dynamic> get(String url, {Map<String, String> params}) async {
|
Future<dynamic> get(String url, {Map<String, String> params, int expectedStatusCode=200}) async {
|
||||||
var _url = makeApiUrl(url);
|
var _url = makeApiUrl(url);
|
||||||
var _headers = defaultHeaders();
|
var _headers = defaultHeaders();
|
||||||
|
|
||||||
@ -455,9 +529,7 @@ class InvenTreeAPI {
|
|||||||
|
|
||||||
print("GET: " + _url);
|
print("GET: " + _url);
|
||||||
|
|
||||||
var client = _client(true);
|
var client = createClient(true);
|
||||||
|
|
||||||
print("Created client");
|
|
||||||
|
|
||||||
HttpClientRequest request = await client.getUrl(Uri.parse(_url));
|
HttpClientRequest request = await client.getUrl(Uri.parse(_url));
|
||||||
|
|
||||||
@ -470,8 +542,6 @@ class InvenTreeAPI {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Created request: ${request.uri}");
|
|
||||||
|
|
||||||
HttpClientResponse response = await request.close()
|
HttpClientResponse response = await request.close()
|
||||||
.timeout(Duration(seconds: 30))
|
.timeout(Duration(seconds: 30))
|
||||||
.catchError((error) {
|
.catchError((error) {
|
||||||
@ -505,7 +575,7 @@ class InvenTreeAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the status code of the response
|
// Check the status code of the response
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != expectedStatusCode) {
|
||||||
showStatusCodeError(response.statusCode);
|
showStatusCodeError(response.statusCode);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:one_context/one_context.dart';
|
import 'package:one_context/one_context.dart';
|
||||||
|
|
||||||
import 'package:device_info/device_info.dart';
|
|
||||||
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
import 'package:qr_code_scanner/qr_code_scanner.dart';
|
||||||
|
|
||||||
import 'package:InvenTree/inventree/stock.dart';
|
import 'package:InvenTree/inventree/stock.dart';
|
||||||
@ -21,7 +20,6 @@ import 'package:InvenTree/widget/part_detail.dart';
|
|||||||
import 'package:InvenTree/widget/stock_detail.dart';
|
import 'package:InvenTree/widget/stock_detail.dart';
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
|
|
||||||
class BarcodeHandler {
|
class BarcodeHandler {
|
||||||
@ -88,49 +86,34 @@ class BarcodeHandler {
|
|||||||
_controller.resumeCamera();
|
_controller.resumeCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> processBarcode(BuildContext context, QRViewController _controller, String barcode, {String url = "barcode/"}) {
|
Future<void> processBarcode(BuildContext context, QRViewController _controller, String barcode, {String url = "barcode/"}) async {
|
||||||
this._context = context;
|
this._context = context;
|
||||||
this._controller = _controller;
|
this._controller = _controller;
|
||||||
|
|
||||||
print("Scanned barcode data: ${barcode}");
|
print("Scanned barcode data: ${barcode}");
|
||||||
|
|
||||||
// Send barcode request to server
|
var data = await InvenTreeAPI().post(
|
||||||
InvenTreeAPI().post(
|
|
||||||
url,
|
url,
|
||||||
body: {
|
body: {
|
||||||
"barcode": barcode
|
"barcode": barcode,
|
||||||
}
|
},
|
||||||
).then((var response) {
|
expectedStatusCode: 200
|
||||||
|
);
|
||||||
if (response.statusCode != 200) {
|
|
||||||
showStatusCodeError(response.statusCode);
|
|
||||||
_controller.resumeCamera();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the response
|
|
||||||
final Map<String, dynamic> data = json.decode(response.body);
|
|
||||||
|
|
||||||
if (data.containsKey('error')) {
|
|
||||||
_controller.resumeCamera();
|
|
||||||
onBarcodeUnknown(data);
|
|
||||||
} else if (data.containsKey('success')) {
|
|
||||||
_controller.resumeCamera();
|
|
||||||
onBarcodeMatched(data);
|
|
||||||
} else {
|
|
||||||
_controller.resumeCamera();
|
|
||||||
onBarcodeUnhandled(data);
|
|
||||||
}
|
|
||||||
}).timeout(
|
|
||||||
Duration(seconds: 5)
|
|
||||||
).catchError((error) {
|
|
||||||
|
|
||||||
showServerError(I18N.of(OneContext().context).error, error.toString());
|
|
||||||
_controller.resumeCamera();
|
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
return;
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (data.containsKey('error')) {
|
||||||
|
_controller.resumeCamera();
|
||||||
|
onBarcodeUnknown(data);
|
||||||
|
} else if (data.containsKey('success')) {
|
||||||
|
_controller.resumeCamera();
|
||||||
|
onBarcodeMatched(data);
|
||||||
|
} else {
|
||||||
|
_controller.resumeCamera();
|
||||||
|
onBarcodeUnhandled(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,36 +262,13 @@ class InvenTreeModel {
|
|||||||
|
|
||||||
InvenTreeModel _model;
|
InvenTreeModel _model;
|
||||||
|
|
||||||
await api.post(URL, body: data).timeout(Duration(seconds: 10)).catchError((e) {
|
var response = await api.post(URL, body: data);
|
||||||
print("Error during CREATE");
|
|
||||||
print(e.toString());
|
|
||||||
|
|
||||||
if (e is SocketException) {
|
|
||||||
showServerError(
|
|
||||||
I18N.of(context).connectionRefused,
|
|
||||||
e.toString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (e is TimeoutException) {
|
|
||||||
showTimeoutError(context);
|
|
||||||
} else {
|
|
||||||
// Re-throw the error
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
return null;
|
return null;
|
||||||
})
|
}
|
||||||
.then((http.Response response) {
|
|
||||||
// Server should return HTTP_201_CREATED
|
|
||||||
if (response.statusCode == 201) {
|
|
||||||
var decoded = json.decode(response.body);
|
|
||||||
_model = createFromJson(decoded);
|
|
||||||
} else {
|
|
||||||
showStatusCodeError(response.statusCode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return _model;
|
return createFromJson(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<InvenTreePageResponse> listPaginated(int limit, int offset, {Map<String, String> filters}) async {
|
Future<InvenTreePageResponse> listPaginated(int limit, int offset, {Map<String, String> filters}) async {
|
||||||
|
@ -437,31 +437,14 @@ class InvenTreeStockItem extends InvenTreeModel {
|
|||||||
endpoint,
|
endpoint,
|
||||||
body: {
|
body: {
|
||||||
"item": {
|
"item": {
|
||||||
"pk": "${pk}",
|
"pk": "${pk}",
|
||||||
"quantity": "${q}",
|
"quantity": "${q}",
|
||||||
},
|
},
|
||||||
"notes": notes ?? '',
|
"notes": notes ?? '',
|
||||||
}).timeout(Duration(seconds: 10)).catchError((error) {
|
|
||||||
if (error is TimeoutException) {
|
|
||||||
showTimeoutError(context);
|
|
||||||
} else if (error is SocketException) {
|
|
||||||
showServerError(
|
|
||||||
I18N.of(context).connectionRefused,
|
|
||||||
error.toString()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Re-throw the error
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Null response if error
|
if (response == null) {
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response == null) return false;
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
showStatusCodeError(response.statusCode);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,9 +491,13 @@ class InvenTreeStockItem extends InvenTreeModel {
|
|||||||
data["item"]["quantity"] = "${quantity}";
|
data["item"]["quantity"] = "${quantity}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("transfer stock!");
|
||||||
|
|
||||||
final response = await api.post("/stock/transfer/", body: data);
|
final response = await api.post("/stock/transfer/", body: data);
|
||||||
|
|
||||||
return (response.statusCode == 200);
|
print("transfer response: ${response}");
|
||||||
|
|
||||||
|
return response != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,8 +208,6 @@ void showFormDialog(String title, {String acceptText, String cancelText, GlobalK
|
|||||||
if (key.currentState.validate()) {
|
if (key.currentState.validate()) {
|
||||||
key.currentState.save();
|
key.currentState.save();
|
||||||
|
|
||||||
print("Saving and closing the dialog");
|
|
||||||
|
|
||||||
// Close the dialog
|
// Close the dialog
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
|
|||||||
|
|
||||||
void _transferStock(BuildContext context, InvenTreeStockLocation location) async {
|
void _transferStock(BuildContext context, InvenTreeStockLocation location) async {
|
||||||
|
|
||||||
double quantity = double.parse(_quantityController.text);
|
double quantity = double.tryParse(_quantityController.text) ?? item.quantity;
|
||||||
String notes = _notesController.text;
|
String notes = _notesController.text;
|
||||||
|
|
||||||
_quantityController.clear();
|
_quantityController.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user