fix: Add option to create Stock Entry from Pick List
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index bd893aa..08a3888 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -28,8 +28,11 @@
frm.call('set_item_locations');
}).addClass('btn-primary');
}
-
- frm.add_custom_button(__('Delivery Note'), () => frm.trigger('make_delivery_note'), __('Create'));
+ if (frm.doc.items_based_on === 'Sales Order') {
+ frm.add_custom_button(__('Delivery Note'), () => frm.trigger('create_delivery_note'), __('Create'));
+ } else {
+ frm.add_custom_button(__('Stock Entry'), () => frm.trigger('create_stock_entry'), __('Create'));
+ }
},
work_order: (frm) => {
frm.clear_table('items');
@@ -42,12 +45,23 @@
items_based_on: (frm) => {
frm.trigger('add_get_items_button');
},
- make_delivery_note(frm) {
+ create_delivery_note(frm) {
frappe.model.open_mapped_doc({
- method: 'erpnext.stock.doctype.pick_list.pick_list.make_delivery_note',
+ method: 'erpnext.stock.doctype.pick_list.pick_list.create_delivery_note',
frm: frm
});
},
+ create_stock_entry(frm) {
+ // TODO: show dialog for qty
+
+ frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.create_stock_entry', {
+ 'pick_list': frm.doc,
+ 'qty': 1
+ }).then(stock_entry => {
+ frappe.model.sync(stock_entry);
+ frappe.set_route("Form", 'Stock Entry', stock_entry.name);
+ });
+ },
add_get_items_button(frm) {
let source_doctype = frm.doc.items_based_on;
if (source_doctype != 'Sales Order') return;
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 8699ee6..34f1ab5 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -4,11 +4,12 @@
from __future__ import unicode_literals
import frappe
-from frappe.model.document import Document
+import json
from six import iteritems
-from frappe.model.mapper import get_mapped_doc, map_child_doc
+from frappe.model.document import Document
from frappe.utils import floor, flt, today
-from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as make_delivery_note_from_sales_order
+from frappe.model.mapper import get_mapped_doc, map_child_doc
+from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note as create_delivery_note_from_sales_order
# TODO: Prioritize SO or WO group warehouse
@@ -49,7 +50,6 @@
def get_items_with_warehouse_and_quantity(item_doc, from_warehouses, item_location_map):
available_locations = item_location_map.get(item_doc.item_code)
-
locations = []
remaining_stock_qty = item_doc.stock_qty
while remaining_stock_qty > 0 and available_locations:
@@ -98,15 +98,6 @@
return available_items
-def set_serial_nos(item_doc):
- serial_nos = frappe.get_all('Serial No', {
- 'item_code': item_doc.item_code,
- 'warehouse': item_doc.warehouse
- }, limit=item_doc.stock_qty, order_by='purchase_date')
- item_doc.set('serial_no', '\n'.join([serial_no.name for serial_no in serial_nos]))
-
- # should we assume that all serialized item_code available in stock will have serial no?
-
def get_item_locations_based_on_serial_nos(item_doc):
serial_nos = frappe.get_all('Serial No',
fields = ['name', 'warehouse'],
@@ -176,26 +167,26 @@
return locations
@frappe.whitelist()
-def make_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)
sales_orders = [d.sales_order for d in pick_list.locations]
sales_orders = set(sales_orders)
delivery_note = None
for sales_order in sales_orders:
- delivery_note = make_delivery_note_from_sales_order(sales_order,
+ delivery_note = create_delivery_note_from_sales_order(sales_order,
delivery_note, skip_item_mapping=True)
for location in pick_list.locations:
sales_order_item = frappe.get_cached_doc('Sales Order Item', location.sales_order_item)
item_table_mapper = {
- "doctype": "Delivery Note Item",
- "field_map": {
- "rate": "rate",
- "name": "so_detail",
- "parent": "against_sales_order",
+ 'doctype': 'Delivery Note Item',
+ 'field_map': {
+ 'rate': 'rate',
+ 'name': 'so_detail',
+ 'parent': 'against_sales_order',
},
- "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
}
dn_item = map_child_doc(sales_order_item, delivery_note, item_table_mapper)
@@ -211,11 +202,6 @@
return delivery_note
-def set_delivery_note_missing_values(target):
- target.run_method("set_missing_values")
- target.run_method("set_po_nos")
- target.run_method("calculate_taxes_and_totals")
-
def update_delivery_note_item(source, target, delivery_note):
cost_center = frappe.db.get_value("Project", delivery_note.project, "cost_center")
if not cost_center:
@@ -238,6 +224,56 @@
target.cost_center = cost_center
+def set_delivery_note_missing_values(target):
+ target.run_method('set_missing_values')
+ target.run_method('set_po_nos')
+ target.run_method('calculate_taxes_and_totals')
+
+
+@frappe.whitelist()
+def create_stock_entry(pick_list, qty):
+ pick_list = frappe.get_doc(json.loads(pick_list))
+ work_order = frappe.get_doc("Work Order", pick_list.get('work_order'))
+ if not qty:
+ qty = work_order.qty - work_order.material_transferred_for_manufacturing
+ if not qty: return
+
+ stock_entry = frappe.new_doc('Stock Entry')
+ stock_entry.purpose = 'Material Transfer For Manufacture'
+ stock_entry.set_stock_entry_type()
+ stock_entry.work_order = work_order.name
+ stock_entry.company = work_order.company
+ stock_entry.from_bom = 1
+ stock_entry.bom_no = work_order.bom_no
+ stock_entry.use_multi_level_bom = work_order.use_multi_level_bom
+ stock_entry.fg_completed_qty = (flt(work_order.qty) - flt(work_order.produced_qty))
+ if work_order.bom_no:
+ stock_entry.inspection_required = frappe.db.get_value('BOM',
+ work_order.bom_no, 'inspection_required')
+
+ is_wip_warehouse_group = frappe.db.get_value('Warehouse', work_order.wip_warehouse, 'is_group')
+ if not (is_wip_warehouse_group and work_order.skip_transfer):
+ wip_warehouse = work_order.wip_warehouse
+ else:
+ wip_warehouse = None
+ stock_entry.to_warehouse = wip_warehouse
+
+ stock_entry.project = work_order.project
+
+ for location in pick_list.locations:
+ item = frappe._dict()
+ item.item_code = location.item_code
+ item.s_warehouse = location.warehouse
+ item.t_warehouse = wip_warehouse
+ item.qty = location.qty
+ item.uom = location.uom
+ item.conversion_factor = location.conversion_factor
+ item.stock_uom = location.stock_uom
+
+ stock_entry.append('items', item)
+
+ return stock_entry.as_dict()
+
@frappe.whitelist()
def get_pending_work_orders(doctype, txt, searchfield, start, page_length, filters, as_dict):
return frappe.db.sql("""