For Material Transfer against Production Order, fetch quantity pending to be transferred for each item.
This commit is contained in:
parent
ab573ce0c7
commit
079f5e0773
@ -1,6 +1,13 @@
|
||||
erpnext.updates = [
|
||||
["21st December 2012", [
|
||||
"Manufacturing: For Material Transfer against Production Order, \
|
||||
fetch quantity pending to be transferred for each item."
|
||||
]],
|
||||
["20th December 2012", [
|
||||
"Website: Create Product Search Page, Product Group Page on the website."
|
||||
"Website: Create Product Search Page, Product Group Page on the website.",
|
||||
"Manufacturing: \
|
||||
<a href=\"https://github.com/webnotes/erpnext/wiki/Changes-in-Manufacturing-Module\" \
|
||||
target=\"_blank\">Refactored code, improved usability.</a>"
|
||||
]],
|
||||
["14th December 2012", [
|
||||
"Website Module: Major Refactor - removed framework code from website."
|
||||
|
@ -46,7 +46,7 @@ var cfn_set_fields = function(doc, dt, dn) {
|
||||
cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Production Order']);
|
||||
|
||||
if (doc.status == 'Submitted' || doc.status == 'Material Transferred' || doc.status == 'In Process'){
|
||||
cur_frm.add_custom_button('Issue Raw Materials', cur_frm.cscript['Issue Raw Materials']);
|
||||
cur_frm.add_custom_button('Transfer Raw Materials', cur_frm.cscript['Transfer Raw Materials']);
|
||||
cur_frm.add_custom_button('Update Finished Goods', cur_frm.cscript['Update Finished Goods']);
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ cur_frm.cscript['Unstop Production Order'] = function() {
|
||||
$c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Issue Raw Materials'] = function() {
|
||||
cur_frm.cscript['Transfer Raw Materials'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
cur_frm.cscript.make_se(doc, 'Material Transfer');
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ wn.provide('erpnext.utils');
|
||||
erpnext.utils.Controller = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
this.setup && this.setup();
|
||||
},
|
||||
|
||||
onload_post_render: function() {
|
||||
|
@ -29,6 +29,7 @@ erpnext.stock.StockEntry = erpnext.utils.Controller.extend({
|
||||
refresh: function() {
|
||||
this._super();
|
||||
this.toggle_related_fields(this.frm.doc);
|
||||
this.toggle_enable_bom();
|
||||
if (this.frm.doc.docstatus==1) this.frm.add_custom_button("Show Stock Ledger",
|
||||
this.show_stock_ledger)
|
||||
},
|
||||
@ -49,6 +50,18 @@ erpnext.stock.StockEntry = erpnext.utils.Controller.extend({
|
||||
refresh_field('mtn_details');
|
||||
},
|
||||
|
||||
production_order: function() {
|
||||
this.toggle_enable_bom();
|
||||
|
||||
this.frm.call({
|
||||
method: "get_production_order_details",
|
||||
args: {production_order: this.frm.doc.production_order}
|
||||
});
|
||||
},
|
||||
|
||||
toggle_enable_bom: function() {
|
||||
this.frm.toggle_enable("bom_no", !this.frm.doc.production_order);
|
||||
},
|
||||
});
|
||||
|
||||
cur_frm.cscript = new erpnext.stock.StockEntry({frm: cur_frm});
|
||||
@ -62,7 +75,7 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
|
||||
|
||||
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("s_warehouse", !disable_from_warehouse);
|
||||
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("t_warehouse", !disable_to_warehouse);
|
||||
|
||||
|
||||
if(doc.purpose == 'Purchase Return') {
|
||||
doc.customer = doc.customer_name = doc.customer_address =
|
||||
doc.delivery_note_no = doc.sales_invoice_no = null;
|
||||
|
@ -32,7 +32,6 @@ class DocType(TransactionBase):
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
self.item_dict = {}
|
||||
self.fname = 'mtn_details'
|
||||
|
||||
def validate(self):
|
||||
@ -229,7 +228,6 @@ class DocType(TransactionBase):
|
||||
self.doc.purpose)
|
||||
|
||||
if self.doc.purpose == 'Purchase Return':
|
||||
#delete_doc("Serial No", serial_no)
|
||||
serial_doc = Document("Serial No", serial_no)
|
||||
serial_doc.status = is_submit and 'Purchase Returned' or 'In Store'
|
||||
serial_doc.docstatus = is_submit and 2 or 0
|
||||
@ -336,11 +334,7 @@ class DocType(TransactionBase):
|
||||
pro_obj = get_obj('Production Order', self.doc.production_order)
|
||||
if pro_obj:
|
||||
self.validate_production_order(pro_obj)
|
||||
|
||||
self.doc.bom_no = pro_obj.doc.bom_no
|
||||
self.doc.fg_completed_qty = (self.doc.purpose == "Manufacture/Repack") \
|
||||
and flt(self.doc.fg_completed_qty) \
|
||||
or flt(pro_obj.doc.qty) - flt(pro_obj.doc.produced_qty)
|
||||
else:
|
||||
# invalid production order
|
||||
self.doc.production_order = None
|
||||
@ -348,12 +342,15 @@ class DocType(TransactionBase):
|
||||
if self.doc.bom_no:
|
||||
if self.doc.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
|
||||
"Subcontract"]:
|
||||
self.get_raw_materials()
|
||||
if self.doc.production_order and self.doc.purpose == "Material Transfer":
|
||||
item_dict = self.get_pending_raw_materials(pro_obj)
|
||||
else:
|
||||
item_dict = self.get_bom_raw_materials(self.doc.fg_completed_qty)
|
||||
|
||||
# add raw materials to Stock Entry Detail table
|
||||
self.add_to_stock_entry_detail(self.doc.from_warehouse, self.doc.to_warehouse,
|
||||
self.item_dict)
|
||||
|
||||
item_dict)
|
||||
|
||||
# add finished good item to Stock Entry Detail table -- along with bom_no
|
||||
if self.doc.production_order and self.doc.purpose == "Manufacture/Repack":
|
||||
self.add_to_stock_entry_detail(None, pro_obj.doc.fg_warehouse, {
|
||||
@ -371,16 +368,28 @@ class DocType(TransactionBase):
|
||||
|
||||
self.get_stock_and_rate()
|
||||
|
||||
def get_raw_materials(self):
|
||||
def get_bom_raw_materials(self, qty):
|
||||
"""
|
||||
get all items from flat bom except
|
||||
child items of sub-contracted and sub assembly items
|
||||
and sub assembly items itself.
|
||||
"""
|
||||
# item dict = { item_code: [qty, description, stock_uom] }
|
||||
item_dict = {}
|
||||
|
||||
def _make_items_dict(items_list):
|
||||
"""makes dict of unique items with it's qty"""
|
||||
for item in items_list:
|
||||
if item_dict.has_key(item.item_code):
|
||||
item_dict[item.item_code][0] += flt(item.qty)
|
||||
else:
|
||||
item_dict[item.item_code] = [flt(item.qty), item.description, item.stock_uom]
|
||||
|
||||
if self.doc.use_multi_level_bom:
|
||||
# get all raw materials with sub assembly childs
|
||||
fl_bom_sa_child_item = sql("""select
|
||||
item_code,ifnull(sum(qty_consumed_per_unit),0)*%s as qty,description,stock_uom
|
||||
item_code,ifnull(sum(qty_consumed_per_unit),0)*%s as qty,
|
||||
description,stock_uom
|
||||
from ( select distinct fb.name, fb.description, fb.item_code,
|
||||
fb.qty_consumed_per_unit, fb.stock_uom
|
||||
from `tabBOM Explosion Item` fb,`tabItem` it
|
||||
@ -388,45 +397,73 @@ class DocType(TransactionBase):
|
||||
and ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus<2
|
||||
and fb.parent=%s
|
||||
) a
|
||||
group by item_code, stock_uom""" , (self.doc.fg_completed_qty, self.doc.bom_no))
|
||||
self.make_items_dict(fl_bom_sa_child_item)
|
||||
group by item_code, stock_uom""" , (qty, self.doc.bom_no), as_dict=1)
|
||||
|
||||
if fl_bom_sa_child_item:
|
||||
_make_items_dict(fl_bom_sa_child_item)
|
||||
else:
|
||||
# Get all raw materials considering multi level BOM,
|
||||
# if multi level bom consider childs of Sub-Assembly items
|
||||
fl_bom_sa_items = sql("""select item_code, ifnull(sum(qty_consumed_per_unit), 0) * '%s',
|
||||
fl_bom_sa_items = sql("""select item_code,
|
||||
ifnull(sum(qty_consumed_per_unit), 0) * '%s' as qty,
|
||||
description, stock_uom from `tabBOM Item`
|
||||
where parent = '%s' and docstatus < 2
|
||||
group by item_code""" % (self.doc.fg_completed_qty, self.doc.bom_no))
|
||||
group by item_code""" % (qty, self.doc.bom_no), as_dict=1)
|
||||
|
||||
self.make_items_dict(fl_bom_sa_items)
|
||||
|
||||
# Update only qty remaining to be issued for production
|
||||
if self.doc.purpose == 'Material Transfer' and self.doc.production_order:
|
||||
self.update_only_remaining_qty()
|
||||
if fl_bom_sa_items:
|
||||
_make_items_dict(fl_bom_sa_items)
|
||||
|
||||
return item_dict
|
||||
|
||||
def make_items_dict(self, items_list):
|
||||
"""makes dict of unique items with it's qty"""
|
||||
for i in items_list:
|
||||
if self.item_dict.has_key(i[0]):
|
||||
self.item_dict[i[0]][0] = flt(self.item_dict[i[0]][0]) + flt(i[1])
|
||||
def get_pending_raw_materials(self, pro_obj):
|
||||
"""
|
||||
issue (item quantity) that is pending to issue or desire to transfer,
|
||||
whichever is less
|
||||
"""
|
||||
item_qty = self.get_bom_raw_materials(1)
|
||||
issued_item_qty = self.get_issued_qty()
|
||||
|
||||
max_qty = flt(pro_obj.doc.qty)
|
||||
only_pending_fetched = []
|
||||
|
||||
for item in item_qty:
|
||||
pending_to_issue = (max_qty * item_qty[item][0]) - issued_item_qty.get(item, 0)
|
||||
desire_to_transfer = flt(self.doc.fg_completed_qty) * item_qty[item][0]
|
||||
|
||||
if desire_to_transfer <= pending_to_issue:
|
||||
item_qty[item][0] = desire_to_transfer
|
||||
else:
|
||||
self.item_dict[i[0]] = [flt(i[1]), cstr(i[2]), cstr(i[3])]
|
||||
item_qty[item][0] = pending_to_issue
|
||||
if pending_to_issue:
|
||||
only_pending_fetched.append(item)
|
||||
|
||||
# delete items with 0 qty
|
||||
for item in item_qty:
|
||||
if not item_qty[item][0]:
|
||||
del item_qty[item]
|
||||
|
||||
# show some message
|
||||
if not len(item_qty):
|
||||
webnotes.msgprint(_("""All items have already been transferred \
|
||||
for this Production Order."""))
|
||||
|
||||
elif only_pending_fetched:
|
||||
webnotes.msgprint(_("""Only quantities pending to be transferred \
|
||||
were fetched for the following items:\n""" + "\n".join(only_pending_fetched)))
|
||||
|
||||
def update_only_remaining_qty(self):
|
||||
""" Only pending raw material to be issued to shop floor """
|
||||
already_issued_item = {}
|
||||
return item_qty
|
||||
|
||||
def get_issued_qty(self):
|
||||
issued_item_qty = {}
|
||||
result = sql("""select t1.item_code, sum(t1.qty)
|
||||
from `tabStock Entry Detail` t1, `tabStock Entry` t2
|
||||
where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1
|
||||
and t2.purpose = 'Material Transfer'
|
||||
group by t1.item_code""", self.doc.production_order)
|
||||
for t in result:
|
||||
already_issued_item[t[0]] = flt(t[1])
|
||||
|
||||
for d in self.item_dict.keys():
|
||||
self.item_dict[d][0] -= already_issued_item.get(d, 0)
|
||||
if self.item_dict[d][0] <= 0:
|
||||
del self.item_dict[d]
|
||||
issued_item_qty[t[0]] = flt(t[1])
|
||||
|
||||
return issued_item_qty
|
||||
|
||||
def add_to_stock_entry_detail(self, source_wh, target_wh, item_dict, bom_no=None):
|
||||
for d in item_dict:
|
||||
@ -440,7 +477,9 @@ class DocType(TransactionBase):
|
||||
se_child.qty = flt(item_dict[d][0])
|
||||
se_child.transfer_qty = flt(item_dict[d][0])
|
||||
se_child.conversion_factor = 1.00
|
||||
if bom_no: se_child.bom_no = bom_no
|
||||
|
||||
# to be assigned for finished item
|
||||
se_child.bom_no = bom_no
|
||||
|
||||
def add_to_values(self, d, wh, qty, is_cancelled):
|
||||
self.values.append({
|
||||
@ -500,3 +539,10 @@ class DocType(TransactionBase):
|
||||
'supplier_name' : res and res[0][0] or '',
|
||||
'supplier_address' : addr and addr[0] or ''}
|
||||
return ret
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_production_order_details(production_order):
|
||||
result = webnotes.conn.sql("""select bom_no,
|
||||
ifnull(qty, 0) - ifnull(produced_qty, 0) as fg_completed_qty
|
||||
from `tabProduction Order` where name = %s""", production_order, as_dict=1)
|
||||
return result and result[0] or {}
|
Loading…
x
Reference in New Issue
Block a user