mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-03 23:05:44 +00:00 
			
		
		
		
	* Handle error on unexpected barcode response * Add ManufacturerPart detail view * Support barcode scanning for manufacturer part * Refactoring for null checks * Ignore selected errors in sentry * Fix API implementation for ManufacturerPart * Update release notes * More error handling * Decode quantity betterer * Refactoring * Add option to confirm checkin details * Improve response handlign * Cleanup * Remove unused imports * Fix async function * Fix for assigning custom barcode * Handle barcode scan result for company * Fix * Adjust scan priority * Refactoring MODEL_TYPE - Use instead of duplicated const strings * @override fix
		
			
				
	
	
		
			330 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import "package:flutter/cupertino.dart";
 | 
						|
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
 | 
						|
import "package:inventree/api.dart";
 | 
						|
import "package:inventree/helpers.dart";
 | 
						|
import "package:inventree/inventree/company.dart";
 | 
						|
import "package:inventree/inventree/model.dart";
 | 
						|
import "package:inventree/inventree/orders.dart";
 | 
						|
import "package:inventree/widget/progress.dart";
 | 
						|
 | 
						|
import "package:inventree/api_form.dart";
 | 
						|
import "package:inventree/l10.dart";
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Class representing an individual PurchaseOrder instance
 | 
						|
 */
 | 
						|
class InvenTreePurchaseOrder extends InvenTreeOrder {
 | 
						|
 | 
						|
  InvenTreePurchaseOrder() : super();
 | 
						|
 | 
						|
  InvenTreePurchaseOrder.fromJson(Map<String, dynamic> json) : super.fromJson(json);
 | 
						|
 | 
						|
  @override
 | 
						|
  InvenTreeModel createFromJson(Map<String, dynamic> json) => InvenTreePurchaseOrder.fromJson(json);
 | 
						|
 | 
						|
  @override
 | 
						|
  String get URL => "order/po/";
 | 
						|
 | 
						|
  static const String MODEL_TYPE = "purchaseorder";
 | 
						|
 | 
						|
  @override
 | 
						|
  List<String> get rolesRequired => ["purchase_order"];
 | 
						|
 | 
						|
  String get receive_url => "${url}receive/";
 | 
						|
 | 
						|
  @override
 | 
						|
  Map<String, Map<String, dynamic>> formFields() {
 | 
						|
    Map<String, Map<String, dynamic>> fields = {
 | 
						|
      "reference": {},
 | 
						|
      "supplier": {
 | 
						|
        "filters": {
 | 
						|
          "is_supplier": true,
 | 
						|
        },
 | 
						|
      },
 | 
						|
      "supplier_reference": {},
 | 
						|
      "description": {},
 | 
						|
      "project_code": {},
 | 
						|
      "destination": {},
 | 
						|
      "target_date": {},
 | 
						|
      "link": {},
 | 
						|
      "responsible": {},
 | 
						|
      "contact": {
 | 
						|
        "filters": {
 | 
						|
          "company": supplierId,
 | 
						|
        }
 | 
						|
      },
 | 
						|
    };
 | 
						|
 | 
						|
    if (!InvenTreeAPI().supportsProjectCodes) {
 | 
						|
      fields.remove("project_code");
 | 
						|
    }
 | 
						|
 | 
						|
    if (!InvenTreeAPI().supportsPurchaseOrderDestination) {
 | 
						|
      fields.remove("destination");
 | 
						|
    }
 | 
						|
 | 
						|
    return fields;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  Map<String, String> defaultFilters() {
 | 
						|
    return {
 | 
						|
      "supplier_detail": "true",
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  int get supplierId => getInt("supplier");
 | 
						|
 | 
						|
  InvenTreeCompany? get supplier {
 | 
						|
 | 
						|
    dynamic supplier_detail = jsondata["supplier_detail"];
 | 
						|
 | 
						|
    if (supplier_detail == null) {
 | 
						|
      return null;
 | 
						|
    } else {
 | 
						|
      return InvenTreeCompany.fromJson(supplier_detail as Map<String, dynamic>);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  String get supplierReference => getString("supplier_reference");
 | 
						|
 | 
						|
  int get destinationId => getInt("destination");
 | 
						|
 | 
						|
  bool get isOpen => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "PLACED", "ON_HOLD"]);
 | 
						|
 | 
						|
  bool get isPending => api.PurchaseOrderStatus.isNameIn(status, ["PENDING", "ON_HOLD"]);
 | 
						|
 | 
						|
  bool get isPlaced => api.PurchaseOrderStatus.isNameIn(status, ["PLACED"]);
 | 
						|
 | 
						|
  bool get isFailed => api.PurchaseOrderStatus.isNameIn(status, ["CANCELLED", "LOST", "RETURNED"]);
 | 
						|
 | 
						|
  Future<List<InvenTreePOLineItem>> getLineItems() async {
 | 
						|
 | 
						|
    final results = await InvenTreePOLineItem().list(
 | 
						|
        filters: {
 | 
						|
          "order": "${pk}",
 | 
						|
        }
 | 
						|
    );
 | 
						|
 | 
						|
    List<InvenTreePOLineItem> items = [];
 | 
						|
 | 
						|
    for (var result in results) {
 | 
						|
      if (result is InvenTreePOLineItem) {
 | 
						|
        items.add(result);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return items;
 | 
						|
  }
 | 
						|
 | 
						|
  /// Mark this order as "placed" / "issued"
 | 
						|
  Future<void> issueOrder() async {
 | 
						|
    // Order can only be placed when the order is 'pending'
 | 
						|
    if (!isPending) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    showLoadingOverlay();
 | 
						|
    await api.post("${url}issue/", expectedStatusCode: 201);
 | 
						|
    hideLoadingOverlay();
 | 
						|
  }
 | 
						|
 | 
						|
  /// Mark this order as "cancelled"
 | 
						|
  Future<void> cancelOrder() async {
 | 
						|
    if (!isOpen) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    showLoadingOverlay();
 | 
						|
    await api.post("${url}cancel/", expectedStatusCode: 201);
 | 
						|
    hideLoadingOverlay();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class InvenTreePOLineItem extends InvenTreeOrderLine {
 | 
						|
 | 
						|
  InvenTreePOLineItem() : super();
 | 
						|
 | 
						|
  InvenTreePOLineItem.fromJson(Map<String, dynamic> json) : super.fromJson(json);
 | 
						|
 | 
						|
  @override
 | 
						|
  InvenTreeModel createFromJson(Map<String, dynamic> json) => InvenTreePOLineItem.fromJson(json);
 | 
						|
 | 
						|
  @override
 | 
						|
  String get URL => "order/po-line/";
 | 
						|
 | 
						|
  @override
 | 
						|
  List<String> get rolesRequired => ["purchase_order"];
 | 
						|
 | 
						|
  @override
 | 
						|
  Map<String, Map<String, dynamic>> formFields() {
 | 
						|
    return {
 | 
						|
      "part": {
 | 
						|
        // We cannot edit the supplier part field here
 | 
						|
        "hidden": true,
 | 
						|
      },
 | 
						|
      "order": {
 | 
						|
        // We cannot edit the order field here
 | 
						|
        "hidden": true,
 | 
						|
      },
 | 
						|
      "reference": {},
 | 
						|
      "quantity": {},
 | 
						|
      "purchase_price": {},
 | 
						|
      "purchase_price_currency": {},
 | 
						|
      "destination": {},
 | 
						|
      "notes": {},
 | 
						|
      "link": {},
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  Map<String, String> defaultFilters() {
 | 
						|
    return {
 | 
						|
      "part_detail": "true",
 | 
						|
      "order_detail": "true",
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  double get received => getDouble("received");
 | 
						|
 | 
						|
  bool get isComplete => received >= quantity;
 | 
						|
 | 
						|
  double get progressRatio {
 | 
						|
    if (quantity <= 0 || received <= 0) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return received / quantity;
 | 
						|
  }
 | 
						|
 | 
						|
  String get progressString => simpleNumberString(received) + " / " + simpleNumberString(quantity);
 | 
						|
 | 
						|
  double get outstanding => quantity - received;
 | 
						|
 | 
						|
  int get supplierPartId => getInt("part");
 | 
						|
 | 
						|
  InvenTreeSupplierPart? get supplierPart {
 | 
						|
 | 
						|
    dynamic detail = jsondata["supplier_part_detail"];
 | 
						|
 | 
						|
    if (detail == null) {
 | 
						|
      return null;
 | 
						|
    } else {
 | 
						|
      return InvenTreeSupplierPart.fromJson(detail as Map<String, dynamic>);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  InvenTreePurchaseOrder? get purchaseOrder {
 | 
						|
    dynamic detail = jsondata["order_detail"];
 | 
						|
 | 
						|
    if (detail == null) {
 | 
						|
      return null;
 | 
						|
    } else {
 | 
						|
      return InvenTreePurchaseOrder.fromJson(detail as Map<String, dynamic>);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  String get SKU => getString("SKU", subKey: "supplier_part_detail");
 | 
						|
 | 
						|
  double get purchasePrice => getDouble("purchase_price");
 | 
						|
  
 | 
						|
  String get purchasePriceCurrency => getString("purchase_price_currency");
 | 
						|
 | 
						|
  int get destinationId => getInt("destination");
 | 
						|
 | 
						|
  Map<String, dynamic> get orderDetail => getMap("order_detail");
 | 
						|
 | 
						|
  Map<String, dynamic> get destinationDetail => getMap("destination_detail");
 | 
						|
 | 
						|
  // Receive this line item into stock
 | 
						|
  Future<void> receive(BuildContext context, {int? destination, double? quantity, String? barcode, Function? onSuccess}) async {
 | 
						|
    // Infer the destination location from the line item if not provided
 | 
						|
    if (destinationId > 0) {
 | 
						|
      destination = destinationId;
 | 
						|
    }
 | 
						|
 | 
						|
    destination ??= (orderDetail["destination"]) as int?;
 | 
						|
 | 
						|
    quantity ??= outstanding;
 | 
						|
 | 
						|
    // Construct form fields
 | 
						|
    Map<String, dynamic> fields = {
 | 
						|
      "line_item": {
 | 
						|
        "parent": "items",
 | 
						|
        "nested": true,
 | 
						|
        "hidden": true,
 | 
						|
        "value": pk,
 | 
						|
      },
 | 
						|
      "quantity": {
 | 
						|
        "parent": "items",
 | 
						|
        "nested": true,
 | 
						|
        "value": quantity,
 | 
						|
      },
 | 
						|
      "location": {},
 | 
						|
      "status": {
 | 
						|
        "parent": "items",
 | 
						|
        "nested": true,
 | 
						|
      },
 | 
						|
      "batch_code": {
 | 
						|
        "parent": "items",
 | 
						|
        "nested": true,
 | 
						|
      },
 | 
						|
      "barcode": {
 | 
						|
        "parent": "items",
 | 
						|
        "nested": true,
 | 
						|
        "type": "barcode",
 | 
						|
        "label": L10().barcodeAssign,
 | 
						|
        "value": barcode,
 | 
						|
        "required": false,
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
    if (destination != null && destination > 0) {
 | 
						|
      fields["location"]?["value"] = destination;
 | 
						|
    }
 | 
						|
 | 
						|
    InvenTreePurchaseOrder? order = purchaseOrder;
 | 
						|
 | 
						|
    if (order != null) {
 | 
						|
      await launchApiForm(
 | 
						|
          context,
 | 
						|
          L10().receiveItem,
 | 
						|
          order.receive_url,
 | 
						|
          fields,
 | 
						|
          method: "POST",
 | 
						|
          icon: TablerIcons.transition_right,
 | 
						|
          onSuccess: (data) {
 | 
						|
            if (onSuccess != null) {
 | 
						|
              onSuccess();
 | 
						|
            }
 | 
						|
          }
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Class representing an attachment file against a PurchaseOrder object
 | 
						|
 */
 | 
						|
class InvenTreePurchaseOrderAttachment extends InvenTreeAttachment {
 | 
						|
 | 
						|
  InvenTreePurchaseOrderAttachment() : super();
 | 
						|
 | 
						|
  InvenTreePurchaseOrderAttachment.fromJson(Map<String, dynamic> json) : super.fromJson(json);
 | 
						|
 | 
						|
  @override
 | 
						|
  String get REFERENCE_FIELD => "order";
 | 
						|
 | 
						|
  @override
 | 
						|
  String get REF_MODEL_TYPE => "purchaseorder";
 | 
						|
 | 
						|
  @override
 | 
						|
  String get URL => InvenTreeAPI().supportsModernAttachments ? "attachment/" : "order/po/attachment/";
 | 
						|
 | 
						|
  @override
 | 
						|
  InvenTreeModel createFromJson(Map<String, dynamic> json) => InvenTreePurchaseOrderAttachment.fromJson(json);
 | 
						|
 | 
						|
}
 |