diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index fa2fe7b4a3c..96e38a9b779 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -148,24 +148,23 @@ def get_data(filters):
for asset in assets_record:
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
- flt(depreciation_amount_map.get(asset.name))
- if asset_value:
- row = {
- "asset_id": asset.name,
- "asset_name": asset.asset_name,
- "status": asset.status,
- "department": asset.department,
- "cost_center": asset.cost_center,
- "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
- "gross_purchase_amount": asset.gross_purchase_amount,
- "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
- "depreciated_amount": depreciation_amount_map.get(asset.name) or 0.0,
- "available_for_use_date": asset.available_for_use_date,
- "location": asset.location,
- "asset_category": asset.asset_category,
- "purchase_date": asset.purchase_date,
- "asset_value": asset_value
- }
- data.append(row)
+ row = {
+ "asset_id": asset.asset_id,
+ "asset_name": asset.asset_name,
+ "status": asset.status,
+ "department": asset.department,
+ "cost_center": asset.cost_center,
+ "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
+ "gross_purchase_amount": asset.gross_purchase_amount,
+ "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
+ "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
+ "available_for_use_date": asset.available_for_use_date,
+ "location": asset.location,
+ "asset_category": asset.asset_category,
+ "purchase_date": asset.purchase_date,
+ "asset_value": asset_value
+ }
+ data.append(row)
return data
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index 215f12c2c2f..45dafd3ab38 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -244,6 +244,15 @@ def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
"""Shipping lines represents the shipping details,
each such shipping detail consists of a list of tax_lines"""
for shipping_charge in shipping_lines:
+ if shipping_charge.get("price"):
+ taxes.append({
+ "charge_type": _("Actual"),
+ "account_head": get_tax_account_head(shipping_charge),
+ "description": shipping_charge["title"],
+ "tax_amount": shipping_charge["price"],
+ "cost_center": shopify_settings.cost_center
+ })
+
for tax in shipping_charge.get("tax_lines"):
taxes.append({
"charge_type": _("Actual"),
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index b243c574d8a..dac61b8e974 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -506,6 +506,39 @@ class TestWorkOrder(unittest.TestCase):
work_order1.save()
self.assertEqual(work_order1.operations[0].time_in_mins, 40.0)
+ def test_partial_material_consumption(self):
+ frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 1)
+ wo_order = make_wo_order_test_record(planned_start_date=now(), qty=4)
+
+ ste_cancel_list = []
+ ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=5000.0)
+ ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
+ target="_Test Warehouse - _TC", qty=20, basic_rate=1000.0)
+
+ ste_cancel_list.extend([ste1, ste2])
+
+ s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 4))
+ s.submit()
+ ste_cancel_list.append(s)
+
+ ste1 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
+ ste1.submit()
+ ste_cancel_list.append(ste1)
+
+ print(wo_order.name)
+ ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
+ self.assertEquals(ste3.fg_completed_qty, 2)
+
+ expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
+ for row in ste3.items:
+ self.assertEquals(row.qty, expected_qty.get(row.item_code))
+
+ for ste_doc in ste_cancel_list:
+ ste_doc.cancel()
+
+ frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
+
def get_scrap_item_details(bom_no):
scrap_items = {}
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index f9c028563bb..13aceaa3601 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -521,7 +521,8 @@ erpnext.work_order = {
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
- if (flt(frm.doc.required_items[i].required_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
+ let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
+ if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
}
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 603c8d4928c..05c2e26b9ca 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -529,7 +529,7 @@ class WorkOrder(Document):
and (entry.purpose = "Material Consumption for Manufacture"
or entry.purpose = "Manufacture")
and entry.docstatus = 1
- and detail.parent = entry.name
+ and detail.parent = entry.name and IFNULL(t_warehouse, "") = ""
and (detail.item_code = %(item)s or detail.original_item = %(item)s)''', {
'name': self.name,
'item': d.item_code
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index a3fe31b465d..dccbc59b2f1 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -2,6 +2,7 @@ import frappe
import numpy as np
from frappe.utils import cint
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
+from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
def get_field_filter_data():
product_settings = get_product_settings()
@@ -249,6 +250,8 @@ def get_next_attribute_and_values(item_code, selected_attributes):
optional_attributes = item_cache.get_optional_attributes()
exact_match = []
+ shopping_cart_settings = get_shopping_cart_settings()
+ allow_items_not_in_stock = cint(shopping_cart_settings.allow_items_not_in_stock)
# search for exact match if all selected attributes are required attributes
if len(selected_attributes.keys()) >= (len(attribute_list) - len(optional_attributes)):
item_attribute_value_map = item_cache.get_item_attribute_value_map()
@@ -263,7 +266,6 @@ def get_next_attribute_and_values(item_code, selected_attributes):
if exact_match:
data = get_product_info_for_website(exact_match[0])
product_info = data.product_info
- product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
if not data.cart_settings.show_price:
product_info = None
else:
@@ -275,6 +277,7 @@ def get_next_attribute_and_values(item_code, selected_attributes):
'filtered_items_count': filtered_items_count,
'filtered_items': filtered_items if filtered_items_count < 10 else [],
'exact_match': exact_match,
+ 'allow_items_not_in_stock': allow_items_not_in_stock,
'product_info': product_info
}
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index fd921cef4e9..8178782c006 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -736,6 +736,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}
},
+ fg_completed_qty: function() {
+ this.get_items();
+ },
+
get_items: function() {
var me = this;
if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
@@ -745,6 +749,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
// if work order / bom is mentioned, get items
return this.frm.call({
doc: me.frm.doc,
+ freeze: true,
method: "get_items",
callback: function(r) {
if(!r.exc) refresh_field("items");
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index b33b4be1979..bb431792740 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1010,26 +1010,22 @@ class StockEntry(StockController):
wo = frappe.get_doc("Work Order", self.work_order)
wo_items = frappe.get_all('Work Order Item',
filters={'parent': self.work_order},
- fields=["item_code", "required_qty", "consumed_qty"]
+ fields=["item_code", "required_qty", "consumed_qty", "transferred_qty"]
)
+ work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
for item in wo_items:
- qty = item.required_qty
-
item_account_details = get_item_defaults(item.item_code, self.company)
# Take into account consumption if there are any.
- if self.purpose == 'Manufacture':
- req_qty_each = flt(item.required_qty / wo.qty)
- if (flt(item.consumed_qty) != 0):
- remaining_qty = flt(item.consumed_qty) - (flt(wo.produced_qty) * req_qty_each)
- exhaust_qty = req_qty_each * wo.produced_qty
- if remaining_qty > exhaust_qty :
- if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
- qty =0
- else:
- qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
- else:
- qty = req_qty_each * flt(self.fg_completed_qty)
+
+ wo_item_qty = item.transferred_qty or item.required_qty
+
+ req_qty_each = (
+ (flt(wo_item_qty) - flt(item.consumed_qty)) /
+ (flt(work_order_qty) - flt(wo.produced_qty))
+ )
+
+ qty = req_qty_each * flt(self.fg_completed_qty)
if qty > 0:
self.add_to_stock_entry_detail({
@@ -1115,13 +1111,15 @@ class StockEntry(StockController):
else:
qty = req_qty_each * flt(self.fg_completed_qty)
-
elif backflushed_materials.get(item.item_code):
for d in backflushed_materials.get(item.item_code):
if d.get(item.warehouse):
if (qty > req_qty):
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
+ if consumed_qty:
+ qty -= consumed_qty
+
if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
qty = frappe.utils.ceil(qty)
diff --git a/erpnext/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js
index 163c955c566..868437a7dcb 100644
--- a/erpnext/templates/generators/item/item_configure.js
+++ b/erpnext/templates/generators/item/item_configure.js
@@ -186,7 +186,7 @@ class ItemConfigure {
this.dialog.$status_area.empty();
}
- get_html_for_item_found({ filtered_items_count, filtered_items, exact_match, product_info }) {
+ get_html_for_item_found({ filtered_items_count, filtered_items, exact_match, product_info, allow_items_not_in_stock }) {
const exact_match_message = __('1 exact match.');
const one_item = exact_match.length === 1 ?
exact_match[0] :
@@ -194,7 +194,7 @@ class ItemConfigure {
filtered_items[0] : '';
// Allow Add to Cart if adding out of stock items enabled in Shopping Cart else check stock.
- const in_stock = product_info.allow_items_not_in_stock ? 1 : product_info.in_stock;
+ const in_stock = allow_items_not_in_stock ? 1 : product_info && product_info.in_stock;
const add_to_cart = `${__('Add to cart')}`;
const product_action = in_stock ? add_to_cart : `${__('Not in Stock')}`;