feat: BOM template (#21262)
Co-authored-by: Marica <maricadsouza221197@gmail.com>
This commit is contained in:
@@ -188,12 +188,6 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
|||||||
# scan description only if items are less than 50000
|
# scan description only if items are less than 50000
|
||||||
description_cond = 'or tabItem.description LIKE %(txt)s'
|
description_cond = 'or tabItem.description LIKE %(txt)s'
|
||||||
|
|
||||||
extra_cond = " and tabItem.has_variants=0"
|
|
||||||
if (filters and isinstance(filters, dict)
|
|
||||||
and filters.get("doctype") == "BOM"):
|
|
||||||
extra_cond = ""
|
|
||||||
del filters["doctype"]
|
|
||||||
|
|
||||||
return frappe.db.sql("""select tabItem.name,
|
return frappe.db.sql("""select tabItem.name,
|
||||||
if(length(tabItem.item_name) > 40,
|
if(length(tabItem.item_name) > 40,
|
||||||
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
|
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
|
||||||
@@ -204,10 +198,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
|||||||
from tabItem
|
from tabItem
|
||||||
where tabItem.docstatus < 2
|
where tabItem.docstatus < 2
|
||||||
and tabItem.disabled=0
|
and tabItem.disabled=0
|
||||||
|
and tabItem.has_variants=0
|
||||||
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
|
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
|
||||||
and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
|
and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
|
||||||
{description_cond})
|
{description_cond})
|
||||||
{extra_cond}
|
|
||||||
{fcond} {mcond}
|
{fcond} {mcond}
|
||||||
order by
|
order by
|
||||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||||
@@ -218,7 +212,6 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
|||||||
key=searchfield,
|
key=searchfield,
|
||||||
columns=columns,
|
columns=columns,
|
||||||
scond=searchfields,
|
scond=searchfields,
|
||||||
extra_cond=extra_cond,
|
|
||||||
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
|
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
|
||||||
mcond=get_match_cond(doctype).replace('%', '%%'),
|
mcond=get_match_cond(doctype).replace('%', '%%'),
|
||||||
description_cond = description_cond),
|
description_cond = description_cond),
|
||||||
|
|||||||
@@ -29,10 +29,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
|
|
||||||
frm.set_query("item", function() {
|
frm.set_query("item", function() {
|
||||||
return {
|
return {
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.manufacturing.doctype.bom.bom.item_query"
|
||||||
filters: {
|
|
||||||
"doctype": "BOM"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,9 +41,12 @@ frappe.ui.form.on("BOM", {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
frm.set_query("item_code", "items", function() {
|
frm.set_query("item_code", "items", function(doc) {
|
||||||
return {
|
return {
|
||||||
query: "erpnext.controllers.queries.item_query"
|
query: "erpnext.manufacturing.doctype.bom.bom.item_query",
|
||||||
|
filters: {
|
||||||
|
"item_code": doc.item
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,6 +96,12 @@ frappe.ui.form.on("BOM", {
|
|||||||
frm.trigger("make_work_order");
|
frm.trigger("make_work_order");
|
||||||
}, __("Create"));
|
}, __("Create"));
|
||||||
|
|
||||||
|
if (frm.doc.has_variants) {
|
||||||
|
frm.add_custom_button(__("Variant BOM"), function() {
|
||||||
|
frm.trigger("make_variant_bom");
|
||||||
|
}, __("Create"));
|
||||||
|
}
|
||||||
|
|
||||||
if (frm.doc.inspection_required) {
|
if (frm.doc.inspection_required) {
|
||||||
frm.add_custom_button(__("Quality Inspection"), function() {
|
frm.add_custom_button(__("Quality Inspection"), function() {
|
||||||
frm.trigger("make_quality_inspection");
|
frm.trigger("make_quality_inspection");
|
||||||
@@ -124,7 +130,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (frm.doc.__onload && frm.doc.__onload["has_variants"]) {
|
if (frm.doc.has_variants) {
|
||||||
frm.set_intro(__('This is a Template BOM and will be used to make the work order for {0} of the item {1}',
|
frm.set_intro(__('This is a Template BOM and will be used to make the work order for {0} of the item {1}',
|
||||||
[
|
[
|
||||||
`<a class="variants-intro">variants</a>`,
|
`<a class="variants-intro">variants</a>`,
|
||||||
@@ -138,9 +144,52 @@ frappe.ui.form.on("BOM", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
make_work_order: function(frm) {
|
make_work_order: function(frm) {
|
||||||
|
frm.events.setup_variant_prompt(frm, "Work Order", (frm, item, data, variant_items) => {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order",
|
||||||
|
args: {
|
||||||
|
bom_no: frm.doc.name,
|
||||||
|
item: item,
|
||||||
|
qty: data.qty || 0.0,
|
||||||
|
project: frm.doc.project,
|
||||||
|
variant_items: variant_items
|
||||||
|
},
|
||||||
|
freeze: true,
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message) {
|
||||||
|
let doc = frappe.model.sync(r.message)[0];
|
||||||
|
frappe.set_route("Form", doc.doctype, doc.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
make_variant_bom: function(frm) {
|
||||||
|
frm.events.setup_variant_prompt(frm, "Variant BOM", (frm, item, data, variant_items) => {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.manufacturing.doctype.bom.bom.make_variant_bom",
|
||||||
|
args: {
|
||||||
|
source_name: frm.doc.name,
|
||||||
|
bom_no: frm.doc.name,
|
||||||
|
item: item,
|
||||||
|
variant_items: variant_items
|
||||||
|
},
|
||||||
|
freeze: true,
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message) {
|
||||||
|
let doc = frappe.model.sync(r.message)[0];
|
||||||
|
frappe.set_route("Form", doc.doctype, doc.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
setup_variant_prompt: function(frm, title, callback, skip_qty_field) {
|
||||||
const fields = [];
|
const fields = [];
|
||||||
|
|
||||||
if (frm.doc.__onload && frm.doc.__onload["has_variants"]) {
|
if (frm.doc.has_variants) {
|
||||||
fields.push({
|
fields.push({
|
||||||
fieldtype: 'Link',
|
fieldtype: 'Link',
|
||||||
label: __('Variant Item'),
|
label: __('Variant Item'),
|
||||||
@@ -158,6 +207,7 @@ frappe.ui.form.on("BOM", {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skip_qty_field) {
|
||||||
fields.push({
|
fields.push({
|
||||||
fieldtype: 'Float',
|
fieldtype: 'Float',
|
||||||
label: __('Qty To Manufacture'),
|
label: __('Qty To Manufacture'),
|
||||||
@@ -165,27 +215,98 @@ frappe.ui.form.on("BOM", {
|
|||||||
reqd: 1,
|
reqd: 1,
|
||||||
default: 1
|
default: 1
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
frappe.prompt(fields, data => {
|
var has_template_rm = frm.doc.items.filter(d => d.has_variants === 1) || [];
|
||||||
let item = data.item || frm.doc.item;
|
if (has_template_rm && has_template_rm.length > 0) {
|
||||||
|
fields.push({
|
||||||
frappe.call({
|
fieldname: "items",
|
||||||
method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order",
|
fieldtype: "Table",
|
||||||
args: {
|
label: __("Raw Materials"),
|
||||||
bom_no: frm.doc.name,
|
fields: [
|
||||||
item: item,
|
{
|
||||||
qty: data.qty || 0.0,
|
fieldname: "item_code",
|
||||||
project: frm.doc.project
|
options: "Item",
|
||||||
|
label: __("Template Item"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
in_list_view: 1,
|
||||||
|
reqd: 1,
|
||||||
},
|
},
|
||||||
freeze: true,
|
{
|
||||||
callback: function(r) {
|
fieldname: "varint_item_code",
|
||||||
if(r.message) {
|
options: "Item",
|
||||||
var doc = frappe.model.sync(r.message)[0];
|
label: __("Variant Item"),
|
||||||
frappe.set_route("Form", doc.doctype, doc.name);
|
fieldtype: "Link",
|
||||||
|
in_list_view: 1,
|
||||||
|
reqd: 1,
|
||||||
|
get_query: function(data) {
|
||||||
|
if (!data.item_code) {
|
||||||
|
frappe.throw(__("Select template item"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: "erpnext.controllers.queries.item_query",
|
||||||
|
filters: {
|
||||||
|
"variant_of": data.item_code
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "qty",
|
||||||
|
label: __("Quantity"),
|
||||||
|
fieldtype: "Float",
|
||||||
|
in_list_view: 1,
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "source_warehouse",
|
||||||
|
label: __("Source Warehouse"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Warehouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: "operation",
|
||||||
|
label: __("Operation"),
|
||||||
|
fieldtype: "Data",
|
||||||
|
hidden: 1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
in_place_edit: true,
|
||||||
|
data: [],
|
||||||
|
get_data: function () {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}, __("Enter Value"), __("Create"));
|
}
|
||||||
|
|
||||||
|
let dialog = frappe.prompt(fields, data => {
|
||||||
|
let item = data.item || frm.doc.item;
|
||||||
|
let variant_items = data.items || [];
|
||||||
|
|
||||||
|
variant_items.forEach(d => {
|
||||||
|
if (!d.varint_item_code) {
|
||||||
|
frappe.throw(__("Select variant item code for the template item {0}", [d.item_code]));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
callback(frm, item, data, variant_items);
|
||||||
|
|
||||||
|
}, __(title), __("Create"));
|
||||||
|
|
||||||
|
has_template_rm.forEach(d => {
|
||||||
|
dialog.fields_dict.items.df.data.push({
|
||||||
|
"item_code": d.item_code,
|
||||||
|
"varint_item_code": "",
|
||||||
|
"qty": d.qty,
|
||||||
|
"source_warehouse": d.source_warehouse,
|
||||||
|
"operation": d.operation
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (has_template_rm) {
|
||||||
|
dialog.fields_dict.items.grid.refresh();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
make_quality_inspection: function(frm) {
|
make_quality_inspection: function(frm) {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"section_break_25",
|
"section_break_25",
|
||||||
"description",
|
"description",
|
||||||
"column_break_27",
|
"column_break_27",
|
||||||
|
"has_variants",
|
||||||
"section_break0",
|
"section_break0",
|
||||||
"exploded_items",
|
"exploded_items",
|
||||||
"website_section",
|
"website_section",
|
||||||
@@ -498,6 +499,17 @@
|
|||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fetch_from": "item.has_variants",
|
||||||
|
"fieldname": "has_variants",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Has Variants",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-sitemap",
|
"icon": "fa fa-sitemap",
|
||||||
@@ -505,7 +517,7 @@
|
|||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-05 14:29:32.634952",
|
"modified": "2020-05-21 12:29:32.634952",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM",
|
"name": "BOM",
|
||||||
|
|||||||
@@ -3,13 +3,16 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, cstr, flt
|
from frappe.utils import cint, cstr, flt, today
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.setup.utils import get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
from frappe.website.website_generator import WebsiteGenerator
|
from frappe.website.website_generator import WebsiteGenerator
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
from erpnext.stock.get_item_details import get_price_list_rate
|
from erpnext.stock.get_item_details import get_price_list_rate
|
||||||
from frappe.core.doctype.version.version import get_diff
|
from frappe.core.doctype.version.version import get_diff
|
||||||
|
from erpnext.controllers.queries import get_match_cond
|
||||||
|
from erpnext.stock.doctype.item.item import get_item_details
|
||||||
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
@@ -59,11 +62,6 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def onload(self):
|
|
||||||
super(BOM, self).onload()
|
|
||||||
if self.get("item") and cint(frappe.db.get_value("Item", self.item, "has_variants")):
|
|
||||||
self.set_onload("has_variants", True)
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.route = frappe.scrub(self.name).replace('_', '-')
|
self.route = frappe.scrub(self.name).replace('_', '-')
|
||||||
self.clear_operations()
|
self.clear_operations()
|
||||||
@@ -103,9 +101,7 @@ class BOM(WebsiteGenerator):
|
|||||||
self.manage_default_bom()
|
self.manage_default_bom()
|
||||||
|
|
||||||
def get_item_det(self, item_code):
|
def get_item_det(self, item_code):
|
||||||
item = frappe.db.sql("""select name, item_name, docstatus, description, image,
|
item = get_item_details(item_code)
|
||||||
is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, include_item_in_manufacturing
|
|
||||||
from `tabItem` where name=%s""", item_code, as_dict = 1)
|
|
||||||
|
|
||||||
if not item:
|
if not item:
|
||||||
frappe.throw(_("Item: {0} does not exist in the system").format(item_code))
|
frappe.throw(_("Item: {0} does not exist in the system").format(item_code))
|
||||||
@@ -150,10 +146,10 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
item = self.get_item_det(args['item_code'])
|
item = self.get_item_det(args['item_code'])
|
||||||
|
|
||||||
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
|
args['bom_no'] = args['bom_no'] or item and cstr(item['default_bom']) or ''
|
||||||
args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or
|
args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or
|
||||||
item and item[0].include_item_in_manufacturing or 0)
|
item and item.include_item_in_manufacturing or 0)
|
||||||
args.update(item[0])
|
args.update(item)
|
||||||
|
|
||||||
rate = self.get_rm_rate(args)
|
rate = self.get_rm_rate(args)
|
||||||
ret_item = {
|
ret_item = {
|
||||||
@@ -185,40 +181,14 @@ class BOM(WebsiteGenerator):
|
|||||||
self.rm_cost_as_per = "Valuation Rate"
|
self.rm_cost_as_per = "Valuation Rate"
|
||||||
|
|
||||||
if arg.get('scrap_items'):
|
if arg.get('scrap_items'):
|
||||||
rate = self.get_valuation_rate(arg)
|
rate = get_valuation_rate(arg)
|
||||||
elif arg:
|
elif arg:
|
||||||
#Customer Provided parts will have zero rate
|
#Customer Provided parts will have zero rate
|
||||||
if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item'):
|
if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item'):
|
||||||
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
|
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
|
||||||
rate = flt(self.get_bom_unitcost(arg['bom_no'])) * (arg.get("conversion_factor") or 1)
|
rate = flt(self.get_bom_unitcost(arg['bom_no'])) * (arg.get("conversion_factor") or 1)
|
||||||
else:
|
else:
|
||||||
if self.rm_cost_as_per == 'Valuation Rate':
|
rate = get_bom_item_rate(arg, self)
|
||||||
rate = self.get_valuation_rate(arg) * (arg.get("conversion_factor") or 1)
|
|
||||||
elif self.rm_cost_as_per == 'Last Purchase Rate':
|
|
||||||
rate = flt(arg.get('last_purchase_rate') \
|
|
||||||
or frappe.db.get_value("Item", arg['item_code'], "last_purchase_rate")) \
|
|
||||||
* (arg.get("conversion_factor") or 1)
|
|
||||||
elif self.rm_cost_as_per == "Price List":
|
|
||||||
if not self.buying_price_list:
|
|
||||||
frappe.throw(_("Please select Price List"))
|
|
||||||
args = frappe._dict({
|
|
||||||
"doctype": "BOM",
|
|
||||||
"price_list": self.buying_price_list,
|
|
||||||
"qty": arg.get("qty") or 1,
|
|
||||||
"uom": arg.get("uom") or arg.get("stock_uom"),
|
|
||||||
"stock_uom": arg.get("stock_uom"),
|
|
||||||
"transaction_type": "buying",
|
|
||||||
"company": self.company,
|
|
||||||
"currency": self.currency,
|
|
||||||
"conversion_rate": 1, # Passed conversion rate as 1 purposefully, as conversion rate is applied at the end of the function
|
|
||||||
"conversion_factor": arg.get("conversion_factor") or 1,
|
|
||||||
"plc_conversion_rate": 1,
|
|
||||||
"ignore_party": True
|
|
||||||
})
|
|
||||||
item_doc = frappe.get_doc("Item", arg.get("item_code"))
|
|
||||||
out = frappe._dict()
|
|
||||||
get_price_list_rate(args, item_doc, out)
|
|
||||||
rate = out.price_list_rate
|
|
||||||
|
|
||||||
if not rate:
|
if not rate:
|
||||||
if self.rm_cost_as_per == "Price List":
|
if self.rm_cost_as_per == "Price List":
|
||||||
@@ -286,31 +256,6 @@ class BOM(WebsiteGenerator):
|
|||||||
where is_active = 1 and name = %s""", bom_no, as_dict=1)
|
where is_active = 1 and name = %s""", bom_no, as_dict=1)
|
||||||
return bom and bom[0]['unit_cost'] or 0
|
return bom and bom[0]['unit_cost'] or 0
|
||||||
|
|
||||||
def get_valuation_rate(self, args):
|
|
||||||
""" Get weighted average of valuation rate from all warehouses """
|
|
||||||
|
|
||||||
total_qty, total_value, valuation_rate = 0.0, 0.0, 0.0
|
|
||||||
for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin`
|
|
||||||
where item_code=%s""", args['item_code'], as_dict=1):
|
|
||||||
total_qty += flt(d.actual_qty)
|
|
||||||
total_value += flt(d.stock_value)
|
|
||||||
|
|
||||||
if total_qty:
|
|
||||||
valuation_rate = total_value / total_qty
|
|
||||||
|
|
||||||
if valuation_rate <= 0:
|
|
||||||
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
|
||||||
from `tabStock Ledger Entry`
|
|
||||||
where item_code = %s and valuation_rate > 0
|
|
||||||
order by posting_date desc, posting_time desc, creation desc limit 1""", args['item_code'])
|
|
||||||
|
|
||||||
valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0
|
|
||||||
|
|
||||||
if not valuation_rate:
|
|
||||||
valuation_rate = frappe.db.get_value("Item", args['item_code'], "valuation_rate")
|
|
||||||
|
|
||||||
return flt(valuation_rate)
|
|
||||||
|
|
||||||
def manage_default_bom(self):
|
def manage_default_bom(self):
|
||||||
""" Uncheck others if current one is selected as default or
|
""" Uncheck others if current one is selected as default or
|
||||||
check the current one as default if it the only bom for the selected item,
|
check the current one as default if it the only bom for the selected item,
|
||||||
@@ -624,6 +569,62 @@ class BOM(WebsiteGenerator):
|
|||||||
if not d.batch_size or d.batch_size <= 0:
|
if not d.batch_size or d.batch_size <= 0:
|
||||||
d.batch_size = 1
|
d.batch_size = 1
|
||||||
|
|
||||||
|
def get_bom_item_rate(args, bom_doc):
|
||||||
|
if bom_doc.rm_cost_as_per == 'Valuation Rate':
|
||||||
|
rate = get_valuation_rate(args) * (args.get("conversion_factor") or 1)
|
||||||
|
elif bom_doc.rm_cost_as_per == 'Last Purchase Rate':
|
||||||
|
rate = ( flt(args.get('last_purchase_rate')) \
|
||||||
|
or frappe.db.get_value("Item", args['item_code'], "last_purchase_rate")) \
|
||||||
|
* (args.get("conversion_factor") or 1)
|
||||||
|
elif bom_doc.rm_cost_as_per == "Price List":
|
||||||
|
if not bom_doc.buying_price_list:
|
||||||
|
frappe.throw(_("Please select Price List"))
|
||||||
|
bom_args = frappe._dict({
|
||||||
|
"doctype": "BOM",
|
||||||
|
"price_list": bom_doc.buying_price_list,
|
||||||
|
"qty": args.get("qty") or 1,
|
||||||
|
"uom": args.get("uom") or args.get("stock_uom"),
|
||||||
|
"stock_uom": args.get("stock_uom"),
|
||||||
|
"transaction_type": "buying",
|
||||||
|
"company": bom_doc.company,
|
||||||
|
"currency": bom_doc.currency,
|
||||||
|
"conversion_rate": 1, # Passed conversion rate as 1 purposefully, as conversion rate is applied at the end of the function
|
||||||
|
"conversion_factor": args.get("conversion_factor") or 1,
|
||||||
|
"plc_conversion_rate": 1,
|
||||||
|
"ignore_party": True
|
||||||
|
})
|
||||||
|
item_doc = frappe.get_cached_doc("Item", args.get("item_code"))
|
||||||
|
out = frappe._dict()
|
||||||
|
get_price_list_rate(bom_args, item_doc, out)
|
||||||
|
rate = out.price_list_rate
|
||||||
|
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def get_valuation_rate(args):
|
||||||
|
""" Get weighted average of valuation rate from all warehouses """
|
||||||
|
|
||||||
|
total_qty, total_value, valuation_rate = 0.0, 0.0, 0.0
|
||||||
|
for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin`
|
||||||
|
where item_code=%s""", args['item_code'], as_dict=1):
|
||||||
|
total_qty += flt(d.actual_qty)
|
||||||
|
total_value += flt(d.stock_value)
|
||||||
|
|
||||||
|
if total_qty:
|
||||||
|
valuation_rate = total_value / total_qty
|
||||||
|
|
||||||
|
if valuation_rate <= 0:
|
||||||
|
last_valuation_rate = frappe.db.sql("""select valuation_rate
|
||||||
|
from `tabStock Ledger Entry`
|
||||||
|
where item_code = %s and valuation_rate > 0
|
||||||
|
order by posting_date desc, posting_time desc, creation desc limit 1""", args['item_code'])
|
||||||
|
|
||||||
|
valuation_rate = flt(last_valuation_rate[0][0]) if last_valuation_rate else 0
|
||||||
|
|
||||||
|
if not valuation_rate:
|
||||||
|
valuation_rate = frappe.db.get_value("Item", args['item_code'], "valuation_rate")
|
||||||
|
|
||||||
|
return flt(valuation_rate)
|
||||||
|
|
||||||
def get_list_context(context):
|
def get_list_context(context):
|
||||||
context.title = _("Bill of Materials")
|
context.title = _("Bill of Materials")
|
||||||
# context.introduction = _('Boms')
|
# context.introduction = _('Boms')
|
||||||
@@ -639,6 +640,8 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
|||||||
sum(bom_item.{qty_field}/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
sum(bom_item.{qty_field}/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
||||||
item.image,
|
item.image,
|
||||||
bom.project,
|
bom.project,
|
||||||
|
bom_item.rate,
|
||||||
|
bom_item.amount,
|
||||||
item.stock_uom,
|
item.stock_uom,
|
||||||
item.item_group,
|
item.item_group,
|
||||||
item.allow_alternative_item,
|
item.allow_alternative_item,
|
||||||
@@ -655,6 +658,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
|||||||
where
|
where
|
||||||
bom_item.docstatus < 2
|
bom_item.docstatus < 2
|
||||||
and bom.name = %(bom)s
|
and bom.name = %(bom)s
|
||||||
|
and ifnull(item.has_variants, 0) = 0
|
||||||
and item.is_stock_item in (1, {is_stock_item})
|
and item.is_stock_item in (1, {is_stock_item})
|
||||||
{where_conditions}
|
{where_conditions}
|
||||||
group by item_code, stock_uom
|
group by item_code, stock_uom
|
||||||
@@ -897,3 +901,84 @@ def get_bom_diff(bom1, bom2):
|
|||||||
out.removed.append([df.fieldname, d.as_dict()])
|
out.removed.append([df.fieldname, d.as_dict()])
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def item_query(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
meta = frappe.get_meta("Item", cached=True)
|
||||||
|
searchfields = meta.get_search_fields()
|
||||||
|
|
||||||
|
order_by = "idx desc, name, item_name"
|
||||||
|
|
||||||
|
fields = ["name", "item_group", "item_name", "description"]
|
||||||
|
fields.extend([field for field in searchfields
|
||||||
|
if not field in ["name", "item_group", "description"]])
|
||||||
|
|
||||||
|
searchfields = searchfields + [field for field in [searchfield or "name", "item_code", "item_group", "item_name"]
|
||||||
|
if not field in searchfields]
|
||||||
|
|
||||||
|
query_filters = {
|
||||||
|
"disabled": 0,
|
||||||
|
"ifnull(end_of_life, '5050-50-50')": (">", today())
|
||||||
|
}
|
||||||
|
|
||||||
|
or_cond_filters = {}
|
||||||
|
if txt:
|
||||||
|
for s_field in searchfields:
|
||||||
|
or_cond_filters[s_field] = ("like", "%{0}%".format(txt))
|
||||||
|
|
||||||
|
barcodes = frappe.get_all("Item Barcode",
|
||||||
|
fields=["distinct parent as item_code"],
|
||||||
|
filters = {"barcode": ("like", "%{0}%".format(txt))})
|
||||||
|
|
||||||
|
barcodes = [d.item_code for d in barcodes]
|
||||||
|
if barcodes:
|
||||||
|
or_cond_filters["name"] = ("in", barcodes)
|
||||||
|
|
||||||
|
for cond in get_match_cond(doctype, as_condition=False):
|
||||||
|
for key, value in cond.items():
|
||||||
|
if key == doctype:
|
||||||
|
key = "name"
|
||||||
|
|
||||||
|
query_filters[key] = ("in", value)
|
||||||
|
|
||||||
|
if filters and filters.get("item_code"):
|
||||||
|
has_variants = frappe.get_cached_value("Item", filters.get("item_code"), "has_variants")
|
||||||
|
if not has_variants:
|
||||||
|
query_filters["has_variants"] = 0
|
||||||
|
|
||||||
|
return frappe.get_all("Item",
|
||||||
|
fields = fields, filters=query_filters,
|
||||||
|
or_filters = or_cond_filters, order_by=order_by,
|
||||||
|
limit_start=start, limit_page_length=page_len, as_list=1)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_variant_bom(source_name, bom_no, item, variant_items, target_doc=None):
|
||||||
|
from erpnext.manufacturing.doctype.work_order.work_order import add_variant_item
|
||||||
|
|
||||||
|
def postprocess(source, doc):
|
||||||
|
doc.item = item
|
||||||
|
doc.quantity = 1
|
||||||
|
|
||||||
|
item_data = get_item_details(item)
|
||||||
|
doc.update({
|
||||||
|
"item_name": item_data.item_name,
|
||||||
|
"description": item_data.description,
|
||||||
|
"uom": item_data.stock_uom,
|
||||||
|
"allow_alternative_item": item_data.allow_alternative_item
|
||||||
|
})
|
||||||
|
|
||||||
|
add_variant_item(variant_items, doc, source_name)
|
||||||
|
|
||||||
|
doc = get_mapped_doc('BOM', source_name, {
|
||||||
|
'BOM': {
|
||||||
|
'doctype': 'BOM',
|
||||||
|
'validation': {
|
||||||
|
'docstatus': ['=', 1]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'BOM Item': {
|
||||||
|
'doctype': 'BOM Item',
|
||||||
|
'condition': lambda doc: doc.has_variants == 0
|
||||||
|
},
|
||||||
|
}, target_doc, postprocess)
|
||||||
|
|
||||||
|
return doc
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
frappe.listview_settings['BOM'] = {
|
frappe.listview_settings['BOM'] = {
|
||||||
add_fields: ["is_active", "is_default", "total_cost"],
|
add_fields: ["is_active", "is_default", "total_cost", "has_variants"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.is_default) {
|
if(doc.is_active && doc.has_variants) {
|
||||||
|
return [__("Template"), "orange", "has_variants,=,Yes"];
|
||||||
|
} else if(doc.is_default) {
|
||||||
return [__("Default"), "green", "is_default,=,Yes"];
|
return [__("Default"), "green", "is_default,=,Yes"];
|
||||||
} else if(doc.is_active) {
|
} else if(doc.is_active) {
|
||||||
return [__("Active"), "blue", "is_active,=,Yes"];
|
return [__("Active"), "blue", "is_active,=,Yes"];
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2013-02-22 01:27:49",
|
"creation": "2013-02-22 01:27:49",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"item_code",
|
"item_code",
|
||||||
"item_name",
|
"item_name",
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
"scrap",
|
"scrap",
|
||||||
"qty_consumed_per_unit",
|
"qty_consumed_per_unit",
|
||||||
"section_break_27",
|
"section_break_27",
|
||||||
|
"has_variants",
|
||||||
"include_item_in_manufacturing",
|
"include_item_in_manufacturing",
|
||||||
"original_item"
|
"original_item"
|
||||||
],
|
],
|
||||||
@@ -57,6 +60,7 @@
|
|||||||
"label": "Item Name"
|
"label": "Item Name"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "eval:parent.with_operations == 1",
|
||||||
"fieldname": "operation",
|
"fieldname": "operation",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Item operation",
|
"label": "Item operation",
|
||||||
@@ -258,11 +262,22 @@
|
|||||||
"label": "Original Item",
|
"label": "Original Item",
|
||||||
"options": "Item",
|
"options": "Item",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fetch_from": "item_code.has_variants",
|
||||||
|
"fieldname": "has_variants",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Has Variants",
|
||||||
|
"no_copy": 1,
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-11-22 11:38:52.087303",
|
"links": [],
|
||||||
|
"modified": "2020-04-09 14:30:26.535546",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM Item",
|
"name": "BOM Item",
|
||||||
|
|||||||
@@ -449,6 +449,32 @@ frappe.ui.form.on("Work Order Item", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
item_code: function(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
|
||||||
|
if (row.item_code) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.stock.doctype.item.item.get_item_details",
|
||||||
|
args: {
|
||||||
|
item_code: row.item_code,
|
||||||
|
company: frm.doc.company
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.message) {
|
||||||
|
frappe.model.set_value(cdt, cdn, {
|
||||||
|
"required_qty": 1,
|
||||||
|
"item_name": r.message.item_name,
|
||||||
|
"description": r.message.description,
|
||||||
|
"source_warehouse": r.message.default_warehouse,
|
||||||
|
"allow_alternative_item": r.message.allow_alternative_item,
|
||||||
|
"include_item_in_manufacturing": r.message.include_item_in_manufacturing
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import math
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form, time_diff_in_hours
|
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form, time_diff_in_hours
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict
|
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict, get_bom_item_rate
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
from erpnext.stock.doctype.item.item import validate_end_of_life, get_item_defaults
|
||||||
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
|
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
|
||||||
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
|
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
|
||||||
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||||
@@ -541,6 +541,8 @@ class WorkOrder(Document):
|
|||||||
# For instance in BOM Explosion Item child table, the items coming from sub assembly items
|
# For instance in BOM Explosion Item child table, the items coming from sub assembly items
|
||||||
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
|
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
|
||||||
self.append('required_items', {
|
self.append('required_items', {
|
||||||
|
'rate': item.rate,
|
||||||
|
'amount': item.amount,
|
||||||
'operation': item.operation,
|
'operation': item.operation,
|
||||||
'item_code': item.item_code,
|
'item_code': item.item_code,
|
||||||
'item_name': item.item_name,
|
'item_name': item.item_name,
|
||||||
@@ -637,9 +639,10 @@ def get_bom_operations(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
filters = filters, fields = ['operation'], as_list=1)
|
filters = filters, fields = ['operation'], as_list=1)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_item_details(item, project = None):
|
def get_item_details(item, project = None, skip_bom_info=False):
|
||||||
res = frappe.db.sql("""
|
res = frappe.db.sql("""
|
||||||
select stock_uom, description
|
select stock_uom, description, item_name, allow_alternative_item,
|
||||||
|
include_item_in_manufacturing
|
||||||
from `tabItem`
|
from `tabItem`
|
||||||
where disabled=0
|
where disabled=0
|
||||||
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)
|
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)
|
||||||
@@ -650,6 +653,7 @@ def get_item_details(item, project = None):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
res = res[0]
|
res = res[0]
|
||||||
|
if skip_bom_info: return res
|
||||||
|
|
||||||
filters = {"item": item, "is_default": 1}
|
filters = {"item": item, "is_default": 1}
|
||||||
|
|
||||||
@@ -681,7 +685,7 @@ def get_item_details(item, project = None):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_work_order(bom_no, item, qty=0, project=None):
|
def make_work_order(bom_no, item, qty=0, project=None, variant_items=None):
|
||||||
if not frappe.has_permission("Work Order", "write"):
|
if not frappe.has_permission("Work Order", "write"):
|
||||||
frappe.throw(_("Not permitted"), frappe.PermissionError)
|
frappe.throw(_("Not permitted"), frappe.PermissionError)
|
||||||
|
|
||||||
@@ -696,8 +700,44 @@ def make_work_order(bom_no, item, qty=0, project=None):
|
|||||||
wo_doc.qty = flt(qty)
|
wo_doc.qty = flt(qty)
|
||||||
wo_doc.get_items_and_operations_from_bom()
|
wo_doc.get_items_and_operations_from_bom()
|
||||||
|
|
||||||
|
if variant_items:
|
||||||
|
add_variant_item(variant_items, wo_doc, bom_no, "required_items")
|
||||||
|
|
||||||
return wo_doc
|
return wo_doc
|
||||||
|
|
||||||
|
def add_variant_item(variant_items, wo_doc, bom_no, table_name="items"):
|
||||||
|
if isinstance(variant_items, string_types):
|
||||||
|
variant_items = json.loads(variant_items)
|
||||||
|
|
||||||
|
for item in variant_items:
|
||||||
|
args = frappe._dict({
|
||||||
|
"item_code": item.get("varint_item_code"),
|
||||||
|
"required_qty": item.get("qty"),
|
||||||
|
"qty": item.get("qty"), # for bom
|
||||||
|
"source_warehouse": item.get("source_warehouse"),
|
||||||
|
"operation": item.get("operation")
|
||||||
|
})
|
||||||
|
|
||||||
|
bom_doc = frappe.get_cached_doc("BOM", bom_no)
|
||||||
|
item_data = get_item_details(args.item_code, skip_bom_info=True)
|
||||||
|
args.update(item_data)
|
||||||
|
|
||||||
|
args["rate"] = get_bom_item_rate({
|
||||||
|
"item_code": args.get("item_code"),
|
||||||
|
"qty": args.get("required_qty"),
|
||||||
|
"uom": args.get("stock_uom"),
|
||||||
|
"stock_uom": args.get("stock_uom"),
|
||||||
|
"conversion_factor": 1
|
||||||
|
}, bom_doc)
|
||||||
|
|
||||||
|
if not args.source_warehouse:
|
||||||
|
args["source_warehouse"] = get_item_defaults(item.get("varint_item_code"),
|
||||||
|
wo_doc.company).default_warehouse
|
||||||
|
|
||||||
|
args["amount"] = flt(args.get("required_qty")) * flt(args.get("rate"))
|
||||||
|
args["uom"] = item_data.stock_uom
|
||||||
|
wo_doc.append(table_name, args)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def check_if_scrap_warehouse_mandatory(bom_no):
|
def check_if_scrap_warehouse_mandatory(bom_no):
|
||||||
res = {"set_scrap_wh_mandatory": False }
|
res = {"set_scrap_wh_mandatory": False }
|
||||||
|
|||||||
@@ -1,526 +1,144 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2016-04-18 07:38:26.314642",
|
"creation": "2016-04-18 07:38:26.314642",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"operation",
|
||||||
|
"item_code",
|
||||||
|
"source_warehouse",
|
||||||
|
"column_break_3",
|
||||||
|
"item_name",
|
||||||
|
"description",
|
||||||
|
"allow_alternative_item",
|
||||||
|
"include_item_in_manufacturing",
|
||||||
|
"qty_section",
|
||||||
|
"required_qty",
|
||||||
|
"rate",
|
||||||
|
"amount",
|
||||||
|
"column_break_11",
|
||||||
|
"transferred_qty",
|
||||||
|
"consumed_qty",
|
||||||
|
"available_qty_at_source_warehouse",
|
||||||
|
"available_qty_at_wip_warehouse"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "operation",
|
"fieldname": "operation",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Operation",
|
"label": "Operation",
|
||||||
"length": 0,
|
"options": "Operation"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Operation",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Item Code",
|
"label": "Item Code",
|
||||||
"length": 0,
|
"options": "Item"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Item",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "source_warehouse",
|
"fieldname": "source_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Source Warehouse",
|
"label": "Source Warehouse",
|
||||||
"length": 0,
|
"options": "Warehouse"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Warehouse",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "item_name",
|
"fieldname": "item_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Item Name",
|
"label": "Item Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Description",
|
"label": "Description",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "qty_section",
|
"fieldname": "qty_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Qty"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Qty",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "required_qty",
|
"fieldname": "required_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Required Qty"
|
||||||
"label": "Required Qty",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:!parent.skip_transfer",
|
"depends_on": "eval:!parent.skip_transfer",
|
||||||
"fieldname": "transferred_qty",
|
"fieldname": "transferred_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Transferred Qty",
|
"label": "Transferred Qty",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "allow_alternative_item",
|
"fieldname": "allow_alternative_item",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Allow Alternative Item"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Allow Alternative Item",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "include_item_in_manufacturing",
|
"fieldname": "include_item_in_manufacturing",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Include Item In Manufacturing"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Include Item In Manufacturing",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_11",
|
"fieldname": "column_break_11",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:!parent.skip_transfer",
|
"depends_on": "eval:!parent.skip_transfer",
|
||||||
"fieldname": "consumed_qty",
|
"fieldname": "consumed_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Consumed Qty",
|
"label": "Consumed Qty",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "available_qty_at_source_warehouse",
|
"fieldname": "available_qty_at_source_warehouse",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Available Qty at Source Warehouse",
|
"label": "Available Qty at Source Warehouse",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "available_qty_at_wip_warehouse",
|
"fieldname": "available_qty_at_wip_warehouse",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Available Qty at WIP Warehouse",
|
"label": "Available Qty at WIP Warehouse",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
},
|
||||||
"permlevel": 0,
|
{
|
||||||
"precision": "",
|
"fieldname": "rate",
|
||||||
"print_hide": 0,
|
"fieldtype": "Currency",
|
||||||
"print_hide_if_no_value": 0,
|
"label": "Rate",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"remember_last_selected_value": 0,
|
},
|
||||||
"report_hide": 0,
|
{
|
||||||
"reqd": 0,
|
"fieldname": "amount",
|
||||||
"search_index": 0,
|
"fieldtype": "Currency",
|
||||||
"set_only_once": 0,
|
"label": "Amount",
|
||||||
"translatable": 0,
|
"read_only": 1
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2018-11-20 19:04:38.508839",
|
"modified": "2020-04-13 18:46:32.966416",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Work Order Item",
|
"name": "Work Order Item",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -1143,6 +1143,17 @@ def set_item_default(item_code, company, fieldname, value):
|
|||||||
d.db_insert()
|
d.db_insert()
|
||||||
item.clear_cache()
|
item.clear_cache()
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_item_details(item_code, company=None):
|
||||||
|
out = frappe._dict()
|
||||||
|
if company:
|
||||||
|
out = get_item_defaults(item_code, company) or frappe._dict()
|
||||||
|
|
||||||
|
doc = frappe.get_cached_doc("Item", item_code)
|
||||||
|
out.update(doc.as_dict())
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_uom_conv_factor(uom, stock_uom):
|
def get_uom_conv_factor(uom, stock_uom):
|
||||||
uoms = [uom, stock_uom]
|
uoms = [uom, stock_uom]
|
||||||
|
|||||||
Reference in New Issue
Block a user