2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

PO Contact (#305)

* Bug fix in API forms

- Allow form fields to specify custom filters at runtime

* Add "contact" model to purchase order edit form

* Add action to create new purchase order from list widget

* widget updates for purchase order
This commit is contained in:
Oliver 2023-04-10 16:59:45 +10:00 committed by GitHub
parent 8631fedbfb
commit 020cc4497c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 20 deletions

View File

@ -285,6 +285,9 @@ class InvenTreeAPI {
// ReturnOrder supports API v104 or newer // ReturnOrder supports API v104 or newer
bool get supportsReturnOrders => isConnected() && apiVersion >= 104; bool get supportsReturnOrders => isConnected() && apiVersion >= 104;
// "Contact" model exposed to API
bool get supportsContactModel => isConnected() && apiVersion >= 104;
// Status label endpoints API v105 or newer // Status label endpoints API v105 or newer
bool get supportsStatusLabelEndpoints => isConnected() && apiVersion >= 105; bool get supportsStatusLabelEndpoints => isConnected() && apiVersion >= 105;

View File

@ -523,18 +523,17 @@ class APIFormField {
), ),
selectedItem: initial_data, selectedItem: initial_data,
asyncItems: (String filter) async { asyncItems: (String filter) async {
Map<String, String> filters = {}; Map<String, String> _filters = {};
filters.forEach((key, value) { filters.forEach((key, value) {
filters[key] = value; _filters[key] = value;
}); });
filters["search"] = filter; _filters["search"] = filter;
filters["offset"] = "0"; _filters["offset"] = "0";
filters["limit"] = "25"; _filters["limit"] = "25";
final APIResponse response = final APIResponse response = await InvenTreeAPI().get(api_url, params: _filters);
await InvenTreeAPI().get(api_url, params: filters);
if (response.isValid()) { if (response.isValid()) {
List<dynamic> results = []; List<dynamic> results = [];
@ -650,6 +649,13 @@ class APIFormField {
title: Text(name), title: Text(name),
leading: FaIcon(isGroup ? FontAwesomeIcons.users : FontAwesomeIcons.user), leading: FaIcon(isGroup ? FontAwesomeIcons.users : FontAwesomeIcons.user),
); );
case "contact":
String name = (data["name"] ?? "") as String;
String role = (data["role"] ?? "") as String;
return ListTile(
title: Text(name),
subtitle: Text(role),
);
case "company": case "company":
var company = InvenTreeCompany.fromJson(data); var company = InvenTreeCompany.fromJson(data);
return ListTile( return ListTile(

View File

@ -26,11 +26,21 @@ class InvenTreePurchaseOrder extends InvenTreeModel {
Map<String, dynamic> formFields() { Map<String, dynamic> formFields() {
return { return {
"reference": {}, "reference": {},
"supplier": {
"filters": {
"is_supplier": true,
},
},
"supplier_reference": {}, "supplier_reference": {},
"description": {}, "description": {},
"target_date": {}, "target_date": {},
"link": {}, "link": {},
"responsible": {}, "responsible": {},
"contact": {
"filters": {
"company": supplierId,
}
},
}; };
} }

View File

@ -726,6 +726,9 @@
"purchaseOrder": "Purchase Order", "purchaseOrder": "Purchase Order",
"@purchaseOrder": {}, "@purchaseOrder": {},
"purchaseOrderCreate": "New Purchase Order",
"@purchaseOrderCreate": {},
"purchaseOrderEdit": "Edit Purchase Order", "purchaseOrderEdit": "Edit Purchase Order",
"@purchaseOrderEdit": {}, "@purchaseOrderEdit": {},

View File

@ -83,11 +83,19 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
); );
} }
// Edit the currently displayed PurchaseOrder
Future <void> editOrder(BuildContext context) async { Future <void> editOrder(BuildContext context) async {
var fields = order.formFields();
fields.remove("supplier");
if (!api.supportsContactModel) {
fields.remove("contact");
}
order.editForm( order.editForm(
context, context,
L10().purchaseOrderEdit, L10().purchaseOrderEdit,
fields: fields,
onSuccess: (data) async { onSuccess: (data) async {
refresh(context); refresh(context);
showSnackIcon(L10().purchaseOrderUpdated, success: true); showSnackIcon(L10().purchaseOrderUpdated, success: true);
@ -143,8 +151,8 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
tiles.add(ListTile( tiles.add(ListTile(
title: Text(L10().lineItems), title: Text(L10().lineItems),
leading: FaIcon(FontAwesomeIcons.clipboardList, color: COLOR_CLICK), leading: FaIcon(FontAwesomeIcons.clipboardCheck),
trailing: Text("${order.lineItemCount}"), trailing: Text("${completedLines} / ${order.lineItemCount}"),
)); ));
tiles.add(ListTile( tiles.add(ListTile(
@ -155,12 +163,6 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
), ),
)); ));
tiles.add(ListTile(
title: Text(L10().received),
leading: FaIcon(FontAwesomeIcons.clipboardCheck, color: COLOR_CLICK),
trailing: Text("${completedLines}"),
));
if (order.issueDate.isNotEmpty) { if (order.issueDate.isNotEmpty) {
tiles.add(ListTile( tiles.add(ListTile(
title: Text(L10().issueDate), title: Text(L10().issueDate),
@ -312,8 +314,6 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
List<Widget> tiles = []; List<Widget> tiles = [];
tiles.add(headerTile(context));
for (var line in lines) { for (var line in lines) {
InvenTreeSupplierPart? supplierPart = line.supplierPart; InvenTreeSupplierPart? supplierPart = line.supplierPart;
@ -347,9 +347,6 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
), ),
), ),
onTap: () { onTap: () {
// TODO: ?
},
onLongPress: () {
lineItemMenu(context, line); lineItemMenu(context, line);
}, },
) )

View File

@ -1,4 +1,5 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_speed_dial/flutter_speed_dial.dart";
import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:font_awesome_flutter/font_awesome_flutter.dart";
import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/company.dart";
@ -47,6 +48,51 @@ class _PurchaseOrderListWidgetState extends RefreshableState<PurchaseOrderListWi
) )
]; ];
@override
List<SpeedDialChild> actionButtons(BuildContext context) {
List<SpeedDialChild> actions = [];
if (api.checkPermission("purchase_order", "add")) {
actions.add(
SpeedDialChild(
child: FaIcon(FontAwesomeIcons.circlePlus),
label: L10().purchaseOrderCreate,
onTap: () {
createPurchaseOrder(context);
}
)
);
}
return actions;
}
Future<void> createPurchaseOrder(BuildContext context) async {
var fields = InvenTreePurchaseOrder().formFields();
fields.remove("contact");
InvenTreePurchaseOrder().createForm(
context,
L10().purchaseOrderCreate,
fields: fields,
onSuccess: (result) async {
Map<String, dynamic> data = result as Map<String, dynamic>;
if (data.containsKey("pk")) {
var order = InvenTreePurchaseOrder.fromJson(data);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PurchaseOrderDetailWidget(order)
)
);
}
}
);
}
@override @override
Widget getBody(BuildContext context) { Widget getBody(BuildContext context) {
return PaginatedPurchaseOrderList(filters, showFilterOptions); return PaginatedPurchaseOrderList(filters, showFilterOptions);