Merge branch 'master' of github.com:webnotes/erpnext
This commit is contained in:
commit
380d7c6a53
@ -1,6 +1,13 @@
|
|||||||
erpnext.updates = [
|
erpnext.updates = [
|
||||||
|
["21st December 2012", [
|
||||||
|
"Manufacturing: For Material Transfer against Production Order, \
|
||||||
|
fetch quantity pending to be transferred for each item."
|
||||||
|
]],
|
||||||
["20th December 2012", [
|
["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", [
|
["14th December 2012", [
|
||||||
"Website Module: Major Refactor - removed framework code from website."
|
"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']);
|
cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Production Order']);
|
||||||
|
|
||||||
if (doc.status == 'Submitted' || doc.status == 'Material Transferred' || doc.status == 'In Process'){
|
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']);
|
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();});
|
$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;
|
var doc = cur_frm.doc;
|
||||||
cur_frm.cscript.make_se(doc, 'Material Transfer');
|
cur_frm.cscript.make_se(doc, 'Material Transfer');
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ wn.provide('erpnext.utils');
|
|||||||
erpnext.utils.Controller = Class.extend({
|
erpnext.utils.Controller = Class.extend({
|
||||||
init: function(opts) {
|
init: function(opts) {
|
||||||
$.extend(this, opts);
|
$.extend(this, opts);
|
||||||
|
this.setup && this.setup();
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render: function() {
|
onload_post_render: function() {
|
||||||
@ -40,13 +41,6 @@ erpnext.utils.Controller = Class.extend({
|
|||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
erpnext.hide_naming_series();
|
erpnext.hide_naming_series();
|
||||||
|
|
||||||
if(this.frm.doc.__islocal && this.frm.fields_dict.naming_series
|
|
||||||
&& !this.frm.doc.naming_series) {
|
|
||||||
var series_opts = $.map((this.frm.fields_dict.naming_series.df.options ||
|
|
||||||
"").split("\n"), function(v) { return v ? v : null; });
|
|
||||||
if (series_opts.length==1) this.frm.set_value("naming_series", series_opts[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,10 +29,26 @@ erpnext.stock.StockEntry = erpnext.utils.Controller.extend({
|
|||||||
refresh: function() {
|
refresh: function() {
|
||||||
this._super();
|
this._super();
|
||||||
this.toggle_related_fields(this.frm.doc);
|
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",
|
if (this.frm.doc.docstatus==1) this.frm.add_custom_button("Show Stock Ledger",
|
||||||
this.show_stock_ledger)
|
this.show_stock_ledger)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
on_submit: function() {
|
||||||
|
this.clean_up();
|
||||||
|
},
|
||||||
|
|
||||||
|
after_cancel: function() {
|
||||||
|
this.clean_up();
|
||||||
|
},
|
||||||
|
|
||||||
|
clean_up: function() {
|
||||||
|
// Clear Production Order record from locals, because it is updated via Stock Entry
|
||||||
|
if(this.frm.doc.production_order && this.frm.doc.purpose == "Manufacture/Repack") {
|
||||||
|
wn.model.clear_doclist("Production Order", this.frm.doc.production_order);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
get_items: function() {
|
get_items: function() {
|
||||||
this.frm.call({
|
this.frm.call({
|
||||||
doc: this.frm.doc,
|
doc: this.frm.doc,
|
||||||
@ -49,6 +65,19 @@ erpnext.stock.StockEntry = erpnext.utils.Controller.extend({
|
|||||||
refresh_field('mtn_details');
|
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});
|
cur_frm.cscript = new erpnext.stock.StockEntry({frm: cur_frm});
|
||||||
|
@ -32,7 +32,6 @@ class DocType(TransactionBase):
|
|||||||
def __init__(self, doc, doclist=[]):
|
def __init__(self, doc, doclist=[]):
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
self.doclist = doclist
|
self.doclist = doclist
|
||||||
self.item_dict = {}
|
|
||||||
self.fname = 'mtn_details'
|
self.fname = 'mtn_details'
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -229,7 +228,6 @@ class DocType(TransactionBase):
|
|||||||
self.doc.purpose)
|
self.doc.purpose)
|
||||||
|
|
||||||
if self.doc.purpose == 'Purchase Return':
|
if self.doc.purpose == 'Purchase Return':
|
||||||
#delete_doc("Serial No", serial_no)
|
|
||||||
serial_doc = Document("Serial No", serial_no)
|
serial_doc = Document("Serial No", serial_no)
|
||||||
serial_doc.status = is_submit and 'Purchase Returned' or 'In Store'
|
serial_doc.status = is_submit and 'Purchase Returned' or 'In Store'
|
||||||
serial_doc.docstatus = is_submit and 2 or 0
|
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)
|
pro_obj = get_obj('Production Order', self.doc.production_order)
|
||||||
if pro_obj:
|
if pro_obj:
|
||||||
self.validate_production_order(pro_obj)
|
self.validate_production_order(pro_obj)
|
||||||
|
|
||||||
self.doc.bom_no = pro_obj.doc.bom_no
|
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:
|
else:
|
||||||
# invalid production order
|
# invalid production order
|
||||||
self.doc.production_order = None
|
self.doc.production_order = None
|
||||||
@ -348,11 +342,14 @@ class DocType(TransactionBase):
|
|||||||
if self.doc.bom_no:
|
if self.doc.bom_no:
|
||||||
if self.doc.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
|
if self.doc.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
|
||||||
"Subcontract"]:
|
"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
|
# add raw materials to Stock Entry Detail table
|
||||||
self.add_to_stock_entry_detail(self.doc.from_warehouse, self.doc.to_warehouse,
|
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
|
# add finished good item to Stock Entry Detail table -- along with bom_no
|
||||||
if self.doc.production_order and self.doc.purpose == "Manufacture/Repack":
|
if self.doc.production_order and self.doc.purpose == "Manufacture/Repack":
|
||||||
@ -371,16 +368,28 @@ class DocType(TransactionBase):
|
|||||||
|
|
||||||
self.get_stock_and_rate()
|
self.get_stock_and_rate()
|
||||||
|
|
||||||
def get_raw_materials(self):
|
def get_bom_raw_materials(self, qty):
|
||||||
"""
|
"""
|
||||||
get all items from flat bom except
|
get all items from flat bom except
|
||||||
child items of sub-contracted and sub assembly items
|
child items of sub-contracted and sub assembly items
|
||||||
and sub assembly items itself.
|
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:
|
if self.doc.use_multi_level_bom:
|
||||||
# get all raw materials with sub assembly childs
|
# get all raw materials with sub assembly childs
|
||||||
fl_bom_sa_child_item = sql("""select
|
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,
|
from ( select distinct fb.name, fb.description, fb.item_code,
|
||||||
fb.qty_consumed_per_unit, fb.stock_uom
|
fb.qty_consumed_per_unit, fb.stock_uom
|
||||||
from `tabBOM Explosion Item` fb,`tabItem` it
|
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 ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus<2
|
||||||
and fb.parent=%s
|
and fb.parent=%s
|
||||||
) a
|
) a
|
||||||
group by item_code, stock_uom""" , (self.doc.fg_completed_qty, self.doc.bom_no))
|
group by item_code, stock_uom""" , (qty, self.doc.bom_no), as_dict=1)
|
||||||
self.make_items_dict(fl_bom_sa_child_item)
|
|
||||||
|
if fl_bom_sa_child_item:
|
||||||
|
_make_items_dict(fl_bom_sa_child_item)
|
||||||
else:
|
else:
|
||||||
# Get all raw materials considering multi level BOM,
|
# Get all raw materials considering multi level BOM,
|
||||||
# if multi level bom consider childs of Sub-Assembly items
|
# 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`
|
description, stock_uom from `tabBOM Item`
|
||||||
where parent = '%s' and docstatus < 2
|
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)
|
if fl_bom_sa_items:
|
||||||
|
_make_items_dict(fl_bom_sa_items)
|
||||||
|
|
||||||
# Update only qty remaining to be issued for production
|
return item_dict
|
||||||
if self.doc.purpose == 'Material Transfer' and self.doc.production_order:
|
|
||||||
self.update_only_remaining_qty()
|
|
||||||
|
|
||||||
def make_items_dict(self, items_list):
|
def get_pending_raw_materials(self, pro_obj):
|
||||||
"""makes dict of unique items with it's qty"""
|
"""
|
||||||
for i in items_list:
|
issue (item quantity) that is pending to issue or desire to transfer,
|
||||||
if self.item_dict.has_key(i[0]):
|
whichever is less
|
||||||
self.item_dict[i[0]][0] = flt(self.item_dict[i[0]][0]) + flt(i[1])
|
"""
|
||||||
|
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:
|
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)
|
||||||
|
|
||||||
def update_only_remaining_qty(self):
|
# delete items with 0 qty
|
||||||
""" Only pending raw material to be issued to shop floor """
|
for item in item_qty:
|
||||||
already_issued_item = {}
|
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)))
|
||||||
|
|
||||||
|
return item_qty
|
||||||
|
|
||||||
|
def get_issued_qty(self):
|
||||||
|
issued_item_qty = {}
|
||||||
result = sql("""select t1.item_code, sum(t1.qty)
|
result = sql("""select t1.item_code, sum(t1.qty)
|
||||||
from `tabStock Entry Detail` t1, `tabStock Entry` t2
|
from `tabStock Entry Detail` t1, `tabStock Entry` t2
|
||||||
where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1
|
where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1
|
||||||
and t2.purpose = 'Material Transfer'
|
and t2.purpose = 'Material Transfer'
|
||||||
group by t1.item_code""", self.doc.production_order)
|
group by t1.item_code""", self.doc.production_order)
|
||||||
for t in result:
|
for t in result:
|
||||||
already_issued_item[t[0]] = flt(t[1])
|
issued_item_qty[t[0]] = flt(t[1])
|
||||||
|
|
||||||
for d in self.item_dict.keys():
|
return issued_item_qty
|
||||||
self.item_dict[d][0] -= already_issued_item.get(d, 0)
|
|
||||||
if self.item_dict[d][0] <= 0:
|
|
||||||
del self.item_dict[d]
|
|
||||||
|
|
||||||
def add_to_stock_entry_detail(self, source_wh, target_wh, item_dict, bom_no=None):
|
def add_to_stock_entry_detail(self, source_wh, target_wh, item_dict, bom_no=None):
|
||||||
for d in item_dict:
|
for d in item_dict:
|
||||||
@ -440,7 +477,9 @@ class DocType(TransactionBase):
|
|||||||
se_child.qty = flt(item_dict[d][0])
|
se_child.qty = flt(item_dict[d][0])
|
||||||
se_child.transfer_qty = flt(item_dict[d][0])
|
se_child.transfer_qty = flt(item_dict[d][0])
|
||||||
se_child.conversion_factor = 1.00
|
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):
|
def add_to_values(self, d, wh, qty, is_cancelled):
|
||||||
self.values.append({
|
self.values.append({
|
||||||
@ -500,3 +539,10 @@ class DocType(TransactionBase):
|
|||||||
'supplier_name' : res and res[0][0] or '',
|
'supplier_name' : res and res[0][0] or '',
|
||||||
'supplier_address' : addr and addr[0] or ''}
|
'supplier_address' : addr and addr[0] or ''}
|
||||||
return ret
|
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