Merge pull request #20962 from marination/pick-list-enhance
fix: Pick List Enhancements
This commit is contained in:
commit
47c8ddb29b
@ -664,3 +664,4 @@ erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
|||||||
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
||||||
erpnext.patches.v12_0.recalculate_requested_qty_in_bin
|
erpnext.patches.v12_0.recalculate_requested_qty_in_bin
|
||||||
erpnext.patches.v12_0.set_total_batch_quantity
|
erpnext.patches.v12_0.set_total_batch_quantity
|
||||||
|
erpnext.patches.v12_0.set_updated_purpose_in_pick_list
|
||||||
|
|||||||
11
erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
Normal file
11
erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Copyright (c) 2019, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("stock", "doctype", "pick_list")
|
||||||
|
frappe.db.sql("""UPDATE `tabPick List` set purpose = 'Delivery'
|
||||||
|
WHERE docstatus = 1 and purpose = 'Delivery against Sales Order' """)
|
||||||
@ -1036,7 +1036,7 @@ def create_pick_list(source_name, target_doc=None):
|
|||||||
},
|
},
|
||||||
}, target_doc)
|
}, target_doc)
|
||||||
|
|
||||||
doc.purpose = 'Delivery against Sales Order'
|
doc.purpose = 'Delivery'
|
||||||
|
|
||||||
doc.set_item_locations()
|
doc.set_item_locations()
|
||||||
|
|
||||||
|
|||||||
@ -38,13 +38,17 @@ frappe.ui.form.on('Pick List', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get_item_locations: (frm) => {
|
set_item_locations:(frm, save) => {
|
||||||
if (!frm.doc.locations || !frm.doc.locations.length) {
|
if (!(frm.doc.locations && frm.doc.locations.length)) {
|
||||||
frappe.msgprint(__('First add items in the Item Locations table'));
|
frappe.msgprint(__('Add items in the Item Locations table'));
|
||||||
} else {
|
} else {
|
||||||
frm.call('set_item_locations');
|
frm.call('set_item_locations', {save: save});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
get_item_locations: (frm) => {
|
||||||
|
// Button on the form
|
||||||
|
frm.events.set_item_locations(frm, false);
|
||||||
|
},
|
||||||
refresh: (frm) => {
|
refresh: (frm) => {
|
||||||
frm.trigger('add_get_items_button');
|
frm.trigger('add_get_items_button');
|
||||||
if (frm.doc.docstatus === 1) {
|
if (frm.doc.docstatus === 1) {
|
||||||
@ -52,8 +56,13 @@ frappe.ui.form.on('Pick List', {
|
|||||||
'pick_list_name': frm.doc.name,
|
'pick_list_name': frm.doc.name,
|
||||||
'purpose': frm.doc.purpose
|
'purpose': frm.doc.purpose
|
||||||
}).then(target_document_exists => {
|
}).then(target_document_exists => {
|
||||||
|
frm.set_df_property("locations", "allow_on_submit", target_document_exists ? 0 : 1);
|
||||||
|
|
||||||
if (target_document_exists) return;
|
if (target_document_exists) return;
|
||||||
if (frm.doc.purpose === 'Delivery against Sales Order') {
|
|
||||||
|
frm.add_custom_button(__('Update Current Stock'), () => frm.trigger('update_pick_list_stock'));
|
||||||
|
|
||||||
|
if (frm.doc.purpose === 'Delivery') {
|
||||||
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
|
frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
|
||||||
} else {
|
} else {
|
||||||
frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
|
frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
|
||||||
@ -105,6 +114,7 @@ frappe.ui.form.on('Pick List', {
|
|||||||
method: 'erpnext.stock.doctype.pick_list.pick_list.create_delivery_note',
|
method: 'erpnext.stock.doctype.pick_list.pick_list.create_delivery_note',
|
||||||
frm: frm
|
frm: frm
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
create_stock_entry: (frm) => {
|
create_stock_entry: (frm) => {
|
||||||
frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
|
frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
|
||||||
@ -114,9 +124,12 @@ frappe.ui.form.on('Pick List', {
|
|||||||
frappe.set_route("Form", 'Stock Entry', stock_entry.name);
|
frappe.set_route("Form", 'Stock Entry', stock_entry.name);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
update_pick_list_stock: (frm) => {
|
||||||
|
frm.events.set_item_locations(frm, true);
|
||||||
|
},
|
||||||
add_get_items_button: (frm) => {
|
add_get_items_button: (frm) => {
|
||||||
let purpose = frm.doc.purpose;
|
let purpose = frm.doc.purpose;
|
||||||
if (purpose != 'Delivery against Sales Order' || frm.doc.docstatus !== 0) return;
|
if (purpose != 'Delivery' || frm.doc.docstatus !== 0) return;
|
||||||
let get_query_filters = {
|
let get_query_filters = {
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
per_delivered: ['<', 100],
|
per_delivered: ['<', 100],
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2019-07-11 16:03:13.681045",
|
"creation": "2019-07-11 16:03:13.681045",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -44,7 +45,7 @@
|
|||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.purpose==='Delivery against Sales Order'",
|
"depends_on": "eval:doc.purpose==='Delivery'",
|
||||||
"fieldname": "customer",
|
"fieldname": "customer",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@ -59,6 +60,7 @@
|
|||||||
"options": "Work Order"
|
"options": "Work Order"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"allow_on_submit": 1,
|
||||||
"fieldname": "locations",
|
"fieldname": "locations",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Item Locations",
|
"label": "Item Locations",
|
||||||
@ -86,7 +88,7 @@
|
|||||||
"fieldname": "purpose",
|
"fieldname": "purpose",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Purpose",
|
"label": "Purpose",
|
||||||
"options": "Material Transfer for Manufacture\nMaterial Transfer\nDelivery against Sales Order"
|
"options": "Material Transfer for Manufacture\nMaterial Transfer\nDelivery"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:['Material Transfer', 'Material Issue'].includes(doc.purpose)",
|
"depends_on": "eval:['Material Transfer', 'Material Issue'].includes(doc.purpose)",
|
||||||
@ -111,7 +113,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-08-29 21:10:11.572387",
|
"links": [],
|
||||||
|
"modified": "2020-03-17 11:38:41.932875",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Pick List",
|
"name": "Pick List",
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class PickList(Document):
|
|||||||
frappe.throw(_('For item {0} at row {1}, count of serial numbers does not match with the picked quantity')
|
frappe.throw(_('For item {0} at row {1}, count of serial numbers does not match with the picked quantity')
|
||||||
.format(frappe.bold(item.item_code), frappe.bold(item.idx)))
|
.format(frappe.bold(item.item_code), frappe.bold(item.idx)))
|
||||||
|
|
||||||
def set_item_locations(self):
|
def set_item_locations(self, save=False):
|
||||||
items = self.aggregate_item_qty()
|
items = self.aggregate_item_qty()
|
||||||
self.item_location_map = frappe._dict()
|
self.item_location_map = frappe._dict()
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class PickList(Document):
|
|||||||
item_code = item_doc.item_code
|
item_code = item_doc.item_code
|
||||||
|
|
||||||
self.item_location_map.setdefault(item_code,
|
self.item_location_map.setdefault(item_code,
|
||||||
get_available_item_locations(item_code, from_warehouses, self.item_count_map.get(item_code)))
|
get_available_item_locations(item_code, from_warehouses, self.item_count_map.get(item_code), self.company))
|
||||||
|
|
||||||
locations = get_items_with_location_and_quantity(item_doc, self.item_location_map)
|
locations = get_items_with_location_and_quantity(item_doc, self.item_location_map)
|
||||||
|
|
||||||
@ -59,12 +59,17 @@ class PickList(Document):
|
|||||||
location.update(row)
|
location.update(row)
|
||||||
self.append('locations', location)
|
self.append('locations', location)
|
||||||
|
|
||||||
|
if save:
|
||||||
|
self.save()
|
||||||
|
|
||||||
def aggregate_item_qty(self):
|
def aggregate_item_qty(self):
|
||||||
locations = self.get('locations')
|
locations = self.get('locations')
|
||||||
self.item_count_map = {}
|
self.item_count_map = {}
|
||||||
# aggregate qty for same item
|
# aggregate qty for same item
|
||||||
item_map = OrderedDict()
|
item_map = OrderedDict()
|
||||||
for item in locations:
|
for item in locations:
|
||||||
|
if not item.item_code:
|
||||||
|
frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx))
|
||||||
item_code = item.item_code
|
item_code = item.item_code
|
||||||
reference = item.sales_order_item or item.material_request_item
|
reference = item.sales_order_item or item.material_request_item
|
||||||
key = (item_code, item.uom, reference)
|
key = (item_code, item.uom, reference)
|
||||||
@ -85,6 +90,10 @@ class PickList(Document):
|
|||||||
return item_map.values()
|
return item_map.values()
|
||||||
|
|
||||||
|
|
||||||
|
def validate_item_locations(pick_list):
|
||||||
|
if not pick_list.locations:
|
||||||
|
frappe.throw(_("Add items in the Item Locations table"))
|
||||||
|
|
||||||
def get_items_with_location_and_quantity(item_doc, item_location_map):
|
def get_items_with_location_and_quantity(item_doc, item_location_map):
|
||||||
available_locations = item_location_map.get(item_doc.item_code)
|
available_locations = item_location_map.get(item_doc.item_code)
|
||||||
locations = []
|
locations = []
|
||||||
@ -130,14 +139,14 @@ def get_items_with_location_and_quantity(item_doc, item_location_map):
|
|||||||
item_location_map[item_doc.item_code] = available_locations
|
item_location_map[item_doc.item_code] = available_locations
|
||||||
return locations
|
return locations
|
||||||
|
|
||||||
def get_available_item_locations(item_code, from_warehouses, required_qty):
|
def get_available_item_locations(item_code, from_warehouses, required_qty, company):
|
||||||
locations = []
|
locations = []
|
||||||
if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
|
if frappe.get_cached_value('Item', item_code, 'has_serial_no'):
|
||||||
locations = get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty)
|
locations = get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty, company)
|
||||||
elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
|
elif frappe.get_cached_value('Item', item_code, 'has_batch_no'):
|
||||||
locations = get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty)
|
locations = get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty, company)
|
||||||
else:
|
else:
|
||||||
locations = get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty)
|
locations = get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty, company)
|
||||||
|
|
||||||
total_qty_available = sum(location.get('qty') for location in locations)
|
total_qty_available = sum(location.get('qty') for location in locations)
|
||||||
|
|
||||||
@ -150,9 +159,10 @@ def get_available_item_locations(item_code, from_warehouses, required_qty):
|
|||||||
return locations
|
return locations
|
||||||
|
|
||||||
|
|
||||||
def get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty):
|
def get_available_item_locations_for_serialized_item(item_code, from_warehouses, required_qty, company):
|
||||||
filters = frappe._dict({
|
filters = frappe._dict({
|
||||||
'item_code': item_code,
|
'item_code': item_code,
|
||||||
|
'company': company,
|
||||||
'warehouse': ['!=', '']
|
'warehouse': ['!=', '']
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -180,7 +190,7 @@ def get_available_item_locations_for_serialized_item(item_code, from_warehouses,
|
|||||||
|
|
||||||
return locations
|
return locations
|
||||||
|
|
||||||
def get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty):
|
def get_available_item_locations_for_batched_item(item_code, from_warehouses, required_qty, company):
|
||||||
warehouse_condition = 'and warehouse in %(warehouses)s' if from_warehouses else ''
|
warehouse_condition = 'and warehouse in %(warehouses)s' if from_warehouses else ''
|
||||||
batch_locations = frappe.db.sql("""
|
batch_locations = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
@ -192,6 +202,7 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
|
|||||||
WHERE
|
WHERE
|
||||||
sle.batch_no = batch.name
|
sle.batch_no = batch.name
|
||||||
and sle.`item_code`=%(item_code)s
|
and sle.`item_code`=%(item_code)s
|
||||||
|
and sle.`company` = %(company)s
|
||||||
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
||||||
{warehouse_condition}
|
{warehouse_condition}
|
||||||
GROUP BY
|
GROUP BY
|
||||||
@ -202,16 +213,20 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
|
|||||||
ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
|
ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`
|
||||||
""".format(warehouse_condition=warehouse_condition), { #nosec
|
""".format(warehouse_condition=warehouse_condition), { #nosec
|
||||||
'item_code': item_code,
|
'item_code': item_code,
|
||||||
|
'company': company,
|
||||||
'today': today(),
|
'today': today(),
|
||||||
'warehouses': from_warehouses
|
'warehouses': from_warehouses
|
||||||
}, as_dict=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
return batch_locations
|
return batch_locations
|
||||||
|
|
||||||
def get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty):
|
def get_available_item_locations_for_other_item(item_code, from_warehouses, required_qty, company):
|
||||||
# gets all items available in different warehouses
|
# gets all items available in different warehouses
|
||||||
|
warehouses = [x.get('name') for x in frappe.get_list("Warehouse", {'company': company}, "name")]
|
||||||
|
|
||||||
filters = frappe._dict({
|
filters = frappe._dict({
|
||||||
'item_code': item_code,
|
'item_code': item_code,
|
||||||
|
'warehouse': ['in', warehouses],
|
||||||
'actual_qty': ['>', 0]
|
'actual_qty': ['>', 0]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -230,7 +245,9 @@ def get_available_item_locations_for_other_item(item_code, from_warehouses, requ
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_delivery_note(source_name, target_doc=None):
|
def create_delivery_note(source_name, target_doc=None):
|
||||||
pick_list = frappe.get_doc('Pick List', source_name)
|
pick_list = frappe.get_doc('Pick List', source_name)
|
||||||
sales_orders = [d.sales_order for d in pick_list.locations]
|
validate_item_locations(pick_list)
|
||||||
|
|
||||||
|
sales_orders = [d.sales_order for d in pick_list.locations if d.sales_order]
|
||||||
sales_orders = set(sales_orders)
|
sales_orders = set(sales_orders)
|
||||||
|
|
||||||
delivery_note = None
|
delivery_note = None
|
||||||
@ -238,6 +255,10 @@ def create_delivery_note(source_name, target_doc=None):
|
|||||||
delivery_note = create_delivery_note_from_sales_order(sales_order,
|
delivery_note = create_delivery_note_from_sales_order(sales_order,
|
||||||
delivery_note, skip_item_mapping=True)
|
delivery_note, skip_item_mapping=True)
|
||||||
|
|
||||||
|
# map rows without sales orders as well
|
||||||
|
if not delivery_note:
|
||||||
|
delivery_note = frappe.new_doc("Delivery Note")
|
||||||
|
|
||||||
item_table_mapper = {
|
item_table_mapper = {
|
||||||
'doctype': 'Delivery Note Item',
|
'doctype': 'Delivery Note Item',
|
||||||
'field_map': {
|
'field_map': {
|
||||||
@ -248,9 +269,25 @@ def create_delivery_note(source_name, target_doc=None):
|
|||||||
'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
|
'condition': lambda doc: abs(doc.delivered_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item_table_mapper_without_so = {
|
||||||
|
'doctype': 'Delivery Note Item',
|
||||||
|
'field_map': {
|
||||||
|
'rate': 'rate',
|
||||||
|
'name': 'name',
|
||||||
|
'parent': '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for location in pick_list.locations:
|
for location in pick_list.locations:
|
||||||
sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
|
if location.sales_order_item:
|
||||||
dn_item = map_child_doc(sales_order_item, delivery_note, item_table_mapper)
|
sales_order_item = frappe.get_cached_doc('Sales Order Item', {'name':location.sales_order_item})
|
||||||
|
else:
|
||||||
|
sales_order_item = None
|
||||||
|
|
||||||
|
source_doc, table_mapper = [sales_order_item, item_table_mapper] if sales_order_item \
|
||||||
|
else [location, item_table_mapper_without_so]
|
||||||
|
|
||||||
|
dn_item = map_child_doc(source_doc, delivery_note, table_mapper)
|
||||||
|
|
||||||
if dn_item:
|
if dn_item:
|
||||||
dn_item.warehouse = location.warehouse
|
dn_item.warehouse = location.warehouse
|
||||||
@ -258,7 +295,7 @@ def create_delivery_note(source_name, target_doc=None):
|
|||||||
dn_item.batch_no = location.batch_no
|
dn_item.batch_no = location.batch_no
|
||||||
dn_item.serial_no = location.serial_no
|
dn_item.serial_no = location.serial_no
|
||||||
|
|
||||||
update_delivery_note_item(sales_order_item, dn_item, delivery_note)
|
update_delivery_note_item(source_doc, dn_item, delivery_note)
|
||||||
|
|
||||||
set_delivery_note_missing_values(delivery_note)
|
set_delivery_note_missing_values(delivery_note)
|
||||||
|
|
||||||
@ -269,6 +306,7 @@ def create_delivery_note(source_name, target_doc=None):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def create_stock_entry(pick_list):
|
def create_stock_entry(pick_list):
|
||||||
pick_list = frappe.get_doc(json.loads(pick_list))
|
pick_list = frappe.get_doc(json.loads(pick_list))
|
||||||
|
validate_item_locations(pick_list)
|
||||||
|
|
||||||
if stock_entry_exists(pick_list.get('name')):
|
if stock_entry_exists(pick_list.get('name')):
|
||||||
return frappe.msgprint(_('Stock Entry has been already created against this Pick List'))
|
return frappe.msgprint(_('Stock Entry has been already created against this Pick List'))
|
||||||
@ -318,7 +356,7 @@ def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filte
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def target_document_exists(pick_list_name, purpose):
|
def target_document_exists(pick_list_name, purpose):
|
||||||
if purpose == 'Delivery against Sales Order':
|
if purpose == 'Delivery':
|
||||||
return frappe.db.exists('Delivery Note', {
|
return frappe.db.exists('Delivery Note', {
|
||||||
'pick_list': pick_list_name
|
'pick_list': pick_list_name
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2019-07-11 16:01:22.832885",
|
"creation": "2019-07-11 16:01:22.832885",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@ -8,6 +9,7 @@
|
|||||||
"item_name",
|
"item_name",
|
||||||
"column_break_2",
|
"column_break_2",
|
||||||
"description",
|
"description",
|
||||||
|
"item_group",
|
||||||
"section_break_5",
|
"section_break_5",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"quantity_section",
|
"quantity_section",
|
||||||
@ -120,7 +122,8 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Item",
|
"label": "Item",
|
||||||
"options": "Item"
|
"options": "Item",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "quantity_section",
|
"fieldname": "quantity_section",
|
||||||
@ -166,10 +169,18 @@
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Material Request Item",
|
"label": "Material Request Item",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "item_code.item_group",
|
||||||
|
"fieldname": "item_group",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Item Group",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-08-29 21:28:39.539007",
|
"links": [],
|
||||||
|
"modified": "2020-03-13 19:08:21.995986",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Pick List Item",
|
"name": "Pick List Item",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user