stock entry cleanup
This commit is contained in:
parent
5f175dfd00
commit
1a6a94b760
@ -299,7 +299,11 @@ class DocType(TransactionBase):
|
|||||||
|
|
||||||
def add_bom(self, d):
|
def add_bom(self, d):
|
||||||
#----- fetching default bom from Bill of Materials instead of Item Master --
|
#----- fetching default bom from Bill of Materials instead of Item Master --
|
||||||
bom_det = sql("select t1.item, t2.item_code, t2.qty_consumed_per_unit, t2.moving_avg_rate, t2.value_as_per_mar, t2.stock_uom, t2.name, t2.parent from `tabBOM` t1, `tabBOM Item` t2 where t2.parent = t1.name and t1.item = '%s' and ifnull(t1.is_default,0) = 1 and t1.docstatus = 1" % d.item_code)
|
bom_det = sql("""select t1.item, t2.item_code, t2.qty_consumed_per_unit,
|
||||||
|
t2.moving_avg_rate, t2.value_as_per_mar, t2.stock_uom, t2.name, t2.parent
|
||||||
|
from `tabBOM` t1, `tabBOM Item` t2
|
||||||
|
where t2.parent = t1.name and t1.item = %s
|
||||||
|
and ifnull(t1.is_default,0) = 1 and t1.docstatus = 1""", (d.item_code,))
|
||||||
|
|
||||||
if not bom_det:
|
if not bom_det:
|
||||||
msgprint("No default BOM exists for item: %s" % d.item_code)
|
msgprint("No default BOM exists for item: %s" % d.item_code)
|
||||||
|
@ -93,21 +93,19 @@ cur_frm.cscript['Unstop Production Order'] = function() {
|
|||||||
|
|
||||||
cur_frm.cscript['Issue Raw Materials'] = function() {
|
cur_frm.cscript['Issue Raw Materials'] = function() {
|
||||||
var doc = cur_frm.doc;
|
var doc = cur_frm.doc;
|
||||||
cur_frm.cscript.make_se(doc, process = 'Material Transfer');
|
cur_frm.cscript.make_se(doc, 'Material Transfer');
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript['Update Finished Goods'] = function() {
|
cur_frm.cscript['Update Finished Goods'] = function() {
|
||||||
var doc = cur_frm.doc;
|
var doc = cur_frm.doc;
|
||||||
cur_frm.cscript.make_se(doc, process = 'Backflush');
|
cur_frm.cscript.make_se(doc, 'Manufacture/Repack');
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.make_se = function(doc, process) {
|
cur_frm.cscript.make_se = function(doc, purpose) {
|
||||||
var se = wn.model.get_new_doc("Stock Entry");
|
var se = wn.model.get_new_doc("Stock Entry");
|
||||||
se.purpose = 'Production Order';
|
se.purpose = purpose;
|
||||||
se.process = process;
|
|
||||||
se.production_order = doc.name;
|
se.production_order = doc.name;
|
||||||
se.company = doc.company;
|
se.company = doc.company;
|
||||||
|
|
||||||
loaddoc('Stock Entry', se.name);
|
loaddoc('Stock Entry', se.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import webnotes
|
|||||||
def execute():
|
def execute():
|
||||||
delete_doctypes()
|
delete_doctypes()
|
||||||
rename_module()
|
rename_module()
|
||||||
rebuilt_exploded_bom()
|
|
||||||
cleanup_bom()
|
cleanup_bom()
|
||||||
|
rebuild_exploded_bom()
|
||||||
|
|
||||||
def delete_doctypes():
|
def delete_doctypes():
|
||||||
from webnotes.model import delete_doc
|
from webnotes.model import delete_doc
|
||||||
@ -36,12 +36,14 @@ def rename_module():
|
|||||||
# set end of life to null if "0000-00-00"
|
# set end of life to null if "0000-00-00"
|
||||||
webnotes.conn.sql("""update `tabItem` set end_of_life=null where end_of_life='0000-00-00'""")
|
webnotes.conn.sql("""update `tabItem` set end_of_life=null where end_of_life='0000-00-00'""")
|
||||||
|
|
||||||
def rebuilt_exploded_bom():
|
def rebuild_exploded_bom():
|
||||||
from webnotes.model.code import get_obj
|
from webnotes.model.code import get_obj
|
||||||
for bom in webnotes.conn.sql("""select name from `tabBOM` where docstatus < 2"""):
|
for bom in webnotes.conn.sql("""select name from `tabBOM` where docstatus < 2"""):
|
||||||
get_obj("BOM", bom[0], with_children=1).on_update()
|
get_obj("BOM", bom[0], with_children=1).on_update()
|
||||||
|
|
||||||
def cleanup_bom():
|
def cleanup_bom():
|
||||||
webnotes.conn.sql("""UPDATE `tabBOM` SET is_active = if(is_active in ('Yes', 1), 1, 0),
|
webnotes.conn.sql("""UPDATE `tabBOM` SET is_active = 1 where ifnull(is_active, 'No') = 'Yes'""")
|
||||||
with_operations = 1""")
|
webnotes.conn.sql("""UPDATE `tabBOM` SET is_active = 0 where ifnull(is_active, 'No') = 'No'""")
|
||||||
|
webnotes.reload_doc("manufacturing", "doctype", "bom")
|
||||||
|
webnotes.conn.sql("""update `tabBOM` set with_operations = 1""")
|
||||||
|
|
@ -12,35 +12,35 @@ def custom_fields():
|
|||||||
"fieldname": "is_excisable_goods",
|
"fieldname": "is_excisable_goods",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"options": "\nYes\nNo",
|
"options": "\nYes\nNo",
|
||||||
"insert_after": "company"
|
"insert_after": "Company"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Excisable Goods",
|
"label": "Excisable Goods",
|
||||||
"fieldname": "excisable_goods",
|
"fieldname": "excisable_goods",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"options": "\nReturnable\nNon-Returnable)",
|
"options": "\nReturnable\nNon-Returnable)",
|
||||||
"insert_after": "amended_from"
|
"insert_after": "Amended From"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Under Rule",
|
"label": "Under Rule",
|
||||||
"fieldname": "under_rule",
|
"fieldname": "under_rule",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"options": "\nOrdinary\n57 AC (5) a\n57 F (2) Non-Exc.",
|
"options": "\nOrdinary\n57 AC (5) a\n57 F (2) Non-Exc.",
|
||||||
"insert_after": "remarks"
|
"insert_after": "Remarks"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Transporter",
|
"label": "Transporter",
|
||||||
"fieldname": "transporter",
|
"fieldname": "transporter",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"options": "",
|
"options": "",
|
||||||
"insert_after": "project_name"
|
"insert_after": "Project Name"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Transfer Date",
|
"label": "Transfer Date",
|
||||||
"fieldname": "transfer_date",
|
"fieldname": "transfer_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"options": "",
|
"options": "",
|
||||||
"insert_after": "select_print_heading"
|
"insert_after": "Select Print Heading"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -62,9 +62,13 @@ def create_custom_field(fld):
|
|||||||
|
|
||||||
def deprecate_process():
|
def deprecate_process():
|
||||||
webnotes.conn.sql("""update `tabStock Entry`
|
webnotes.conn.sql("""update `tabStock Entry`
|
||||||
set `purpose`="Production Order - Material Transfer"
|
set `purpose`="Material Transfer"
|
||||||
where process="Material Transfer" and purpose="Production Order" """)
|
where process="Material Transfer" and purpose="Production Order" """)
|
||||||
|
|
||||||
webnotes.conn.sql("""update `tabStock Entry`
|
webnotes.conn.sql("""update `tabStock Entry`
|
||||||
set `purpose`="Production Order - Update Finished Goods"
|
set `purpose`="Manufacture/Repack"
|
||||||
where process="Backflush" and purpose="Production Order" """)
|
where (process="Backflush" and purpose="Production Order") or purpose="Other" """)
|
||||||
|
|
||||||
|
webnotes.conn.sql("""update `tabStock Entry`
|
||||||
|
set `purpose`="Subcontract"
|
||||||
|
where process="Subcontracting" """)
|
@ -542,4 +542,8 @@ patch_list = [
|
|||||||
'patch_module': 'patches.december_2012',
|
'patch_module': 'patches.december_2012',
|
||||||
'patch_file': 'clear_web_cache',
|
'patch_file': 'clear_web_cache',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'patch_module': 'patches.december_2012',
|
||||||
|
'patch_file': 'stock_entry_cleanup',
|
||||||
|
},
|
||||||
]
|
]
|
@ -19,71 +19,19 @@ cur_frm.cscript.refresh = function(doc) {
|
|||||||
cur_frm.cscript.toggle_related_fields(doc);
|
cur_frm.cscript.toggle_related_fields(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.toggle_related_fields = function(doc) {
|
cur_frm.cscript.toggle_related_fields = function(doc) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(doc.purpose.startswith("Production Order") || doc.purpose == "Other") {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (doc.purpose == 'Production Order' || doc.purpose == 'Other') {
|
|
||||||
unhide_field('get_items');
|
|
||||||
hide_field(['from_warehouse', 'to_warehouse','purchase_receipt_no',
|
|
||||||
'delivery_note_no', 'sales_invoice_no','warehouse_html']);
|
|
||||||
if (doc.purpose=='Production Order') unhide_field(['production_order', 'process']);
|
|
||||||
else {
|
|
||||||
doc.production_order = doc.process = '';
|
|
||||||
hide_field(['production_order', 'process']);
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.from_warehouse = '';
|
|
||||||
doc.to_warehouse = '';
|
|
||||||
refresh_field(['from_warehosue', 'to_warehouse']);
|
|
||||||
if (doc.process == 'Backflush' || doc.purpose == 'Other') {
|
|
||||||
unhide_field('fg_completed_qty');
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
hide_field('fg_completed_qty');
|
|
||||||
doc.fg_completed_qty = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unhide_field(['from_warehouse', 'to_warehouse']);
|
|
||||||
hide_field(['production_order', 'process', 'get_items', 'fg_completed_qty',
|
|
||||||
'purchase_receipt_no','delivery_note_no', 'sales_invoice_no']);
|
|
||||||
doc.production_order = '';
|
|
||||||
doc.process = '';
|
|
||||||
doc.fg_completed_qty = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(doc.purpose == 'Purchase Return') {
|
if(doc.purpose == 'Purchase Return') {
|
||||||
doc.customer = doc.customer_name = doc.customer_address =
|
doc.customer = doc.customer_name = doc.customer_address =
|
||||||
doc.delivery_note_no = doc.sales_invoice_no = '';
|
doc.delivery_note_no = doc.sales_invoice_no = null;
|
||||||
unhide_field(['supplier','supplier_name','supplier_address','purchase_receipt_no']);
|
doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
|
||||||
$(cur_frm.fields_dict.contact_section.row.wrapper).toggle(true);
|
} else if(doc.purpose == 'Sales Return') {
|
||||||
}
|
doc.supplier=doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no=null;
|
||||||
else if(doc.purpose == 'Sales Return'){
|
doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
|
||||||
doc.supplier=doc.supplier_name = doc.supplier_address=doc.purchase_receipt_no='';
|
} else {
|
||||||
unhide_field(['customer', 'customer_name', 'customer_address',
|
|
||||||
'delivery_note_no', 'sales_invoice_no']);
|
|
||||||
$(cur_frm.fields_dict.contact_section.row.wrapper).toggle(true);
|
|
||||||
} else{
|
|
||||||
doc.customer = doc.customer_name = doc.customer_address =
|
doc.customer = doc.customer_name = doc.customer_address =
|
||||||
doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
|
doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
|
||||||
doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = '';
|
doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null;
|
||||||
}
|
}
|
||||||
refresh_many(lst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.delivery_note_no = function(doc,cdt,cdn){
|
cur_frm.cscript.delivery_note_no = function(doc,cdt,cdn){
|
||||||
@ -108,43 +56,41 @@ cur_frm.cscript.supplier = function(doc,cdt,cdn){
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.fields_dict['production_order'].get_query = function(doc) {
|
cur_frm.fields_dict['production_order'].get_query = function(doc) {
|
||||||
return 'SELECT DISTINCT `tabProduction Order`.`name` FROM `tabProduction Order` WHERE `tabProduction Order`.`docstatus` = 1 AND `tabProduction Order`.`qty` > ifnull(`tabProduction Order`.`produced_qty`,0) AND `tabProduction Order`.`name` like "%s" ORDER BY `tabProduction Order`.`name` DESC LIMIT 50';
|
return 'select name from `tabProduction Order` \
|
||||||
|
where docstatus = 1 and qty > ifnull(produced_qty,0) AND %(key)s like "%s%%" \
|
||||||
|
order by name desc limit 50';
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.purpose = function(doc, cdt, cdn) {
|
cur_frm.cscript.purpose = function(doc, cdt, cdn) {
|
||||||
cur_frm.cscript.toggle_related_fields(doc, cdt, cdn);
|
cur_frm.cscript.toggle_related_fields(doc, cdt, cdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.process = function(doc, cdt, cdn) {
|
|
||||||
cur_frm.cscript.toggle_related_fields(doc, cdt, cdn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// item code - only if quantity present in source warehosue
|
// item code - only if quantity present in source warehosue
|
||||||
//
|
|
||||||
var fld = cur_frm.fields_dict['mtn_details'].grid.get_field('item_code');
|
var fld = cur_frm.fields_dict['mtn_details'].grid.get_field('item_code');
|
||||||
fld.query_description = "If Source Warehouse is selected, only items present in the warehouse with actual qty > 0 will be selected"
|
fld.query_description = "If Source Warehouse is selected, items with existing stock \
|
||||||
|
for that warehouse will be selected";
|
||||||
|
|
||||||
fld.get_query = function(doc, cdt, cdn) {
|
fld.get_query = function(doc, cdt, cdn) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
|
|
||||||
if(d.s_warehouse) {
|
if(d.s_warehouse) {
|
||||||
return 'SELECT tabItem.name, tabItem.description, tabBin.actual_qty '
|
return 'SELECT tabItem.name, tabItem.description, tabBin.actual_qty '
|
||||||
+'FROM tabItem, tabBin '
|
+ 'FROM tabItem, tabBin '
|
||||||
+'WHERE tabItem.name = tabBin.item_code '
|
+ 'WHERE tabItem.name = tabBin.item_code '
|
||||||
+'AND ifnull(`tabBin`.`actual_qty`,0) > 0 '
|
+ 'AND ifnull(`tabBin`.`actual_qty`,0) > 0 '
|
||||||
+'AND tabBin.warehouse="'+ d.s_warehouse +'" '
|
+ 'AND tabBin.warehouse="'+ d.s_warehouse +'" '
|
||||||
+'AND tabItem.docstatus < 2 '
|
+ 'AND tabItem.docstatus < 2 '
|
||||||
+'AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") '
|
+ 'AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") '
|
||||||
+'AND tabItem.%(key)s LIKE "%s" '
|
+ 'AND tabItem.%(key)s LIKE "%s" '
|
||||||
+'ORDER BY tabItem.name ASC '
|
+ 'ORDER BY tabItem.name ASC '
|
||||||
+'LIMIT 50'
|
+ 'LIMIT 50'
|
||||||
} else {
|
} else {
|
||||||
return 'SELECT tabItem.name, tabItem.description '
|
return 'SELECT tabItem.name, tabItem.description '
|
||||||
+'FROM tabItem '
|
+ 'FROM tabItem '
|
||||||
+'WHERE tabItem.docstatus < 2 '
|
+ 'WHERE tabItem.docstatus < 2 '
|
||||||
+'AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") '
|
+ 'AND (ifnull(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` > NOW() OR `tabItem`.`end_of_life`="0000-00-00") '
|
||||||
+'AND tabItem.%(key)s LIKE "%s" '
|
+ 'AND tabItem.%(key)s LIKE "%s" '
|
||||||
+'ORDER BY tabItem.name ASC '
|
+ 'ORDER BY tabItem.name ASC '
|
||||||
+'LIMIT 50'
|
+ 'LIMIT 50'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +136,6 @@ cur_frm.cscript.item_code = function(doc, cdt, cdn) {
|
|||||||
'warehouse' : cstr(d.s_warehouse) || cstr(d.t_warehouse),
|
'warehouse' : cstr(d.s_warehouse) || cstr(d.t_warehouse),
|
||||||
'transfer_qty' : d.transfer_qty,
|
'transfer_qty' : d.transfer_qty,
|
||||||
'serial_no' : d.serial_no,
|
'serial_no' : d.serial_no,
|
||||||
'fg_item' : d.fg_item,
|
|
||||||
'bom_no' : d.bom_no
|
'bom_no' : d.bom_no
|
||||||
};
|
};
|
||||||
get_server_fields('get_item_details',JSON.stringify(args),'mtn_details',doc,cdt,cdn,1);
|
get_server_fields('get_item_details',JSON.stringify(args),'mtn_details',doc,cdt,cdn,1);
|
||||||
@ -203,7 +148,6 @@ cur_frm.cscript.s_warehouse = function(doc, cdt, cdn) {
|
|||||||
'warehouse' : cstr(d.s_warehouse) || cstr(d.t_warehouse),
|
'warehouse' : cstr(d.s_warehouse) || cstr(d.t_warehouse),
|
||||||
'transfer_qty' : d.transfer_qty,
|
'transfer_qty' : d.transfer_qty,
|
||||||
'serial_no' : d.serial_no,
|
'serial_no' : d.serial_no,
|
||||||
'fg_item' : d.fg_item,
|
|
||||||
'bom_no' : d.bom_no
|
'bom_no' : d.bom_no
|
||||||
}
|
}
|
||||||
get_server_fields('get_warehouse_details', JSON.stringify(args),
|
get_server_fields('get_warehouse_details', JSON.stringify(args),
|
||||||
@ -212,16 +156,10 @@ cur_frm.cscript.s_warehouse = function(doc, cdt, cdn) {
|
|||||||
|
|
||||||
cur_frm.cscript.t_warehouse = cur_frm.cscript.s_warehouse;
|
cur_frm.cscript.t_warehouse = cur_frm.cscript.s_warehouse;
|
||||||
|
|
||||||
cur_frm.cscript.transfer_qty = function(doc,cdt,cdn) {
|
|
||||||
var d = locals[cdt][cdn];
|
|
||||||
if (doc.from_warehouse && (flt(d.transfer_qty) > flt(d.actual_qty))) {
|
|
||||||
alert("Transfer Quantity is more than Available Qty");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.qty = function(doc, cdt, cdn) {
|
cur_frm.cscript.qty = function(doc, cdt, cdn) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
set_multiple('Stock Entry Detail', d.name, {'transfer_qty': flt(d.qty) * flt(d.conversion_factor)}, 'mtn_details');
|
set_multiple('Stock Entry Detail', d.name,
|
||||||
|
{'transfer_qty': flt(d.qty) * flt(d.conversion_factor)}, 'mtn_details');
|
||||||
refresh_field('mtn_details');
|
refresh_field('mtn_details');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,18 @@ class DocType(TransactionBase):
|
|||||||
self.validate_bom()
|
self.validate_bom()
|
||||||
self.validate_finished_goods()
|
self.validate_finished_goods()
|
||||||
|
|
||||||
|
def on_submit(self):
|
||||||
|
self.update_serial_no(1)
|
||||||
|
self.update_stock_ledger(0)
|
||||||
|
# update Production Order
|
||||||
|
self.update_production_order(1)
|
||||||
|
|
||||||
|
def on_cancel(self):
|
||||||
|
self.update_serial_no(0)
|
||||||
|
self.update_stock_ledger(1)
|
||||||
|
# update Production Order
|
||||||
|
self.update_production_order(0)
|
||||||
|
|
||||||
def validate_serial_nos(self):
|
def validate_serial_nos(self):
|
||||||
sl_obj = get_obj("Stock Ledger")
|
sl_obj = get_obj("Stock Ledger")
|
||||||
sl_obj.scrub_serial_nos(self)
|
sl_obj.scrub_serial_nos(self)
|
||||||
@ -56,10 +68,8 @@ class DocType(TransactionBase):
|
|||||||
def validate_warehouse(self, pro_obj):
|
def validate_warehouse(self, pro_obj):
|
||||||
"""perform various (sometimes conditional) validations on warehouse"""
|
"""perform various (sometimes conditional) validations on warehouse"""
|
||||||
|
|
||||||
source_mandatory = ["Material Issue", "Material Transfer",
|
source_mandatory = ["Material Issue", "Material Transfer", "Purchase Return"]
|
||||||
"Production Order - Material Transfer", "Purchase Return"]
|
target_mandatory = ["Material Receipt", "Material Transfer", "Sales Return"]
|
||||||
target_mandatory = ["Material Receipt", "Material Transfer",
|
|
||||||
"Production Order - Material Transfer", "Sales Return"]
|
|
||||||
|
|
||||||
fg_qty = 0
|
fg_qty = 0
|
||||||
for d in getlist(self.doclist, 'mtn_details'):
|
for d in getlist(self.doclist, 'mtn_details'):
|
||||||
@ -89,11 +99,15 @@ class DocType(TransactionBase):
|
|||||||
if self.doc.purpose not in source_mandatory:
|
if self.doc.purpose not in source_mandatory:
|
||||||
d.s_warehouse = None
|
d.s_warehouse = None
|
||||||
|
|
||||||
if self.doc.purpose == "Production Order - Update Finished Goods":
|
if self.doc.purpose == "Manufacture/Repack":
|
||||||
if d.item_code == pro_obj.doc.item:
|
if d.bom_no:
|
||||||
d.s_warehouse = None
|
d.s_warehouse = None
|
||||||
|
|
||||||
if cstr(d.t_warehouse) != pro_obj.doc.fg_warehouse:
|
if not d.t_warehouse:
|
||||||
|
msgprint(_("Row # ") + "%s: " % cint(d.idx)
|
||||||
|
+ _("Target Warehouse") + _(" is mandatory"), raise_exception=1)
|
||||||
|
|
||||||
|
elif pro_obj and cstr(d.t_warehouse) != pro_obj.doc.fg_warehouse:
|
||||||
msgprint(_("Row # ") + "%s: " % cint(d.idx)
|
msgprint(_("Row # ") + "%s: " % cint(d.idx)
|
||||||
+ _("Target Warehouse") + _(" should be same as that in ")
|
+ _("Target Warehouse") + _(" should be same as that in ")
|
||||||
+ _("Production Order"), raise_exception=1)
|
+ _("Production Order"), raise_exception=1)
|
||||||
@ -104,18 +118,14 @@ class DocType(TransactionBase):
|
|||||||
msgprint(_("Row # ") + "%s: " % cint(d.idx)
|
msgprint(_("Row # ") + "%s: " % cint(d.idx)
|
||||||
+ _("Source Warehouse") + _(" is mandatory"), raise_exception=1)
|
+ _("Source Warehouse") + _(" is mandatory"), raise_exception=1)
|
||||||
|
|
||||||
# if self.doc.fg_completed_qty and flt(self.doc.fg_completed_qty) != flt(fg_qty):
|
|
||||||
# msgprint("The Total of FG Qty %s in Stock Entry Detail do not match with FG Completed Qty %s" % (flt(fg_qty), flt(self.doc.fg_completed_qty)))
|
|
||||||
# raise Exception
|
|
||||||
|
|
||||||
def validate_production_order(self, pro_obj=None):
|
def validate_production_order(self, pro_obj=None):
|
||||||
if not pro_obj:
|
if not pro_obj:
|
||||||
|
if self.doc.production_order:
|
||||||
pro_obj = get_obj('Production Order', self.doc.production_order)
|
pro_obj = get_obj('Production Order', self.doc.production_order)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
if self.doc.purpose == "Production Order - Material Transfer":
|
if self.doc.purpose == "Manufacture/Repack":
|
||||||
self.doc.fg_completed_qty = 0
|
|
||||||
|
|
||||||
elif self.doc.purpose == "Production Order - Update Finished Goods":
|
|
||||||
if not flt(self.doc.fg_completed_qty):
|
if not flt(self.doc.fg_completed_qty):
|
||||||
msgprint(_("Manufacturing Quantity") + _(" is mandatory"), raise_exception=1)
|
msgprint(_("Manufacturing Quantity") + _(" is mandatory"), raise_exception=1)
|
||||||
|
|
||||||
@ -128,7 +138,7 @@ class DocType(TransactionBase):
|
|||||||
+ _("Hence, maximum allowed Manufacturing Quantity")
|
+ _("Hence, maximum allowed Manufacturing Quantity")
|
||||||
+ " = %s." % flt(pro_obj.doc.qty) - flt(pro_obj.doc.produced_qty),
|
+ " = %s." % flt(pro_obj.doc.qty) - flt(pro_obj.doc.produced_qty),
|
||||||
raise_exception=1)
|
raise_exception=1)
|
||||||
else:
|
elif self.doc.purpose != "Material Transfer":
|
||||||
self.doc.production_order = None
|
self.doc.production_order = None
|
||||||
|
|
||||||
def get_stock_and_rate(self):
|
def get_stock_and_rate(self):
|
||||||
@ -184,16 +194,88 @@ class DocType(TransactionBase):
|
|||||||
+ _(" or the BOM is cancelled or inactive"), raise_exception=1)
|
+ _(" or the BOM is cancelled or inactive"), raise_exception=1)
|
||||||
|
|
||||||
def validate_finished_goods(self):
|
def validate_finished_goods(self):
|
||||||
|
"""validation: finished good quantity should be same as manufacturing quantity"""
|
||||||
for d in getlist(self.doclist, 'mtn_details'):
|
for d in getlist(self.doclist, 'mtn_details'):
|
||||||
if d.bom_no and flt(d.transfer_qty) != flt(self.doc.fg_completed_qty):
|
if d.bom_no and flt(d.transfer_qty) != flt(self.doc.fg_completed_qty):
|
||||||
|
msgprint(_("Row #") + " %s: " % d.idx
|
||||||
|
+ _("Quantity as per Stock UOM should be equal to Manufacturing Quantity"),
|
||||||
|
raise_exception=1)
|
||||||
|
|
||||||
|
def update_serial_no(self, is_submit):
|
||||||
|
"""Create / Update Serial No"""
|
||||||
|
sl_obj = get_obj('Stock Ledger')
|
||||||
|
if is_submit:
|
||||||
|
sl_obj.validate_serial_no_warehouse(self, 'mtn_details')
|
||||||
|
|
||||||
|
for d in getlist(self.doclist, 'mtn_details'):
|
||||||
|
if d.serial_no:
|
||||||
|
serial_nos = sl_obj.get_sr_no_list(d.serial_no)
|
||||||
|
for x in serial_nos:
|
||||||
|
serial_no = x.strip()
|
||||||
|
if d.s_warehouse:
|
||||||
|
sl_obj.update_serial_delivery_details(self, d, serial_no, is_submit)
|
||||||
|
if d.t_warehouse:
|
||||||
|
sl_obj.update_serial_purchase_details(self, d, serial_no, is_submit,
|
||||||
|
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
|
||||||
|
serial_doc.save()
|
||||||
|
|
||||||
|
def update_stock_ledger(self, is_cancelled=0):
|
||||||
|
self.values = []
|
||||||
|
for d in getlist(self.doclist, 'mtn_details'):
|
||||||
|
if cstr(d.s_warehouse):
|
||||||
|
self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled)
|
||||||
|
if cstr(d.t_warehouse):
|
||||||
|
self.add_to_values(d, cstr(d.t_warehouse), flt(d.transfer_qty), is_cancelled)
|
||||||
|
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values,
|
||||||
|
self.doc.amended_from and 'Yes' or 'No')
|
||||||
|
|
||||||
|
def update_production_order(self, is_submit):
|
||||||
|
if self.doc.production_order:
|
||||||
|
# first perform some validations
|
||||||
|
# (they are here coz this fn is also called during on_cancel)
|
||||||
|
pro_obj = get_obj("Production Order", self.doc.production_order)
|
||||||
|
if flt(pro_obj.doc.docstatus) != 1:
|
||||||
|
msgprint("""You cannot do any transaction against
|
||||||
|
Production Order : %s, as it's not submitted"""
|
||||||
|
% (pro_obj.doc.name), raise_exception=1)
|
||||||
|
|
||||||
|
if pro_obj.doc.status == 'Stopped':
|
||||||
|
msgprint("""You cannot do any transaction against Production Order : %s,
|
||||||
|
as it's status is 'Stopped'"""% (pro_obj.doc.name), raise_exception=1)
|
||||||
|
|
||||||
|
if getdate(pro_obj.doc.posting_date) > getdate(self.doc.posting_date):
|
||||||
|
msgprint("""Posting Date of Stock Entry cannot be before Posting Date of
|
||||||
|
Production Order: %s"""% cstr(self.doc.production_order), raise_exception=1)
|
||||||
|
|
||||||
|
# update bin
|
||||||
|
if self.doc.purpose == "Manufacture/Repack":
|
||||||
|
pro_obj.doc.produced_qty = flt(pro_obj.doc.produced_qty) + \
|
||||||
|
(is_submit and 1 or -1 ) * flt(self.doc.fg_completed_qty)
|
||||||
|
args = {
|
||||||
|
"item_code": pro_obj.doc.production_item,
|
||||||
|
"posting_date": self.doc.posting_date,
|
||||||
|
"planned_qty": (is_submit and -1 or 1 ) * flt(self.doc.fg_completed_qty)
|
||||||
|
}
|
||||||
|
get_obj('Warehouse', pro_obj.doc.fg_warehouse).update_bin(args)
|
||||||
|
|
||||||
|
# update production order status
|
||||||
|
pro_obj.doc.status = (flt(pro_obj.doc.qty)==flt(pro_obj.doc.produced_qty)) \
|
||||||
|
and 'Completed' or 'In Process'
|
||||||
|
pro_obj.doc.save()
|
||||||
|
|
||||||
def get_item_details(self, arg):
|
def get_item_details(self, arg):
|
||||||
import json
|
import json
|
||||||
arg, actual_qty, in_rate = json.loads(arg), 0, 0
|
arg, actual_qty, in_rate = json.loads(arg), 0, 0
|
||||||
|
|
||||||
item = sql("select stock_uom, description, item_name from `tabItem` where name = %s and (ifnull(end_of_life,'')='' or end_of_life ='0000-00-00' or end_of_life > now())", (arg.get('item_code')), as_dict = 1)
|
item = sql("""select stock_uom, description, item_name from `tabItem`
|
||||||
|
where name = %s and (ifnull(end_of_life,'')='' or end_of_life ='0000-00-00'
|
||||||
|
or end_of_life > now())""", (arg.get('item_code')), as_dict = 1)
|
||||||
if not item:
|
if not item:
|
||||||
msgprint("Item is not active", raise_exception=1)
|
msgprint("Item is not active", raise_exception=1)
|
||||||
|
|
||||||
@ -213,12 +295,13 @@ class DocType(TransactionBase):
|
|||||||
ret.update(stock_and_rate)
|
ret.update(stock_and_rate)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_uom_details(self, arg = ''):
|
def get_uom_details(self, arg = ''):
|
||||||
arg, ret = eval(arg), {}
|
arg, ret = eval(arg), {}
|
||||||
uom = sql("select conversion_factor from `tabUOM Conversion Detail` where parent = %s and uom = %s", (arg['item_code'],arg['uom']), as_dict = 1)
|
uom = sql("""select conversion_factor from `tabUOM Conversion Detail`
|
||||||
|
where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1)
|
||||||
if not uom:
|
if not uom:
|
||||||
msgprint("There is no Conversion Factor for UOM '%s' in Item '%s'" % (arg['uom'], arg['item_code']))
|
msgprint("There is no Conversion Factor for UOM '%s' in Item '%s'" % (arg['uom'],
|
||||||
|
arg['item_code']))
|
||||||
ret = {'uom' : ''}
|
ret = {'uom' : ''}
|
||||||
else:
|
else:
|
||||||
ret = {
|
ret = {
|
||||||
@ -235,114 +318,31 @@ class DocType(TransactionBase):
|
|||||||
self.doc.posting_date, self.doc.posting_time),
|
self.doc.posting_date, self.doc.posting_time),
|
||||||
"incoming_rate" : self.get_incoming_rate(arg.get('item_code'),
|
"incoming_rate" : self.get_incoming_rate(arg.get('item_code'),
|
||||||
arg.get('warehouse'), self.doc.posting_date, self.doc.posting_time,
|
arg.get('warehouse'), self.doc.posting_date, self.doc.posting_time,
|
||||||
arg.get('transfer_qty'), arg.get('serial_no'), arg.get('fg_item'),
|
arg.get('transfer_qty'), arg.get('serial_no'), arg.get('bom_no')) or 0
|
||||||
arg.get('bom_no')) or 0
|
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
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])
|
|
||||||
else:
|
|
||||||
self.item_dict[i[0]] = [flt(i[1]), cstr(i[2]), cstr(i[3])]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_only_remaining_qty(self):
|
|
||||||
""" Only pending raw material to be issued to shop floor """
|
|
||||||
already_issued_item = {}
|
|
||||||
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.purpose = 'Production Order - Material Transfer'
|
|
||||||
and t2.docstatus = 1 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]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_raw_materials(self, bom_no, fg_qty, use_multi_level_bom):
|
|
||||||
"""
|
|
||||||
get all items from flat bom except
|
|
||||||
child items of sub-contracted and sub assembly items
|
|
||||||
and sub assembly items itself.
|
|
||||||
"""
|
|
||||||
if 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
|
|
||||||
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
|
|
||||||
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
|
||||||
and ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus<2 and fb.parent=%s
|
|
||||||
) a
|
|
||||||
group by item_code,stock_uom
|
|
||||||
""" , (fg_qty, bom_no))
|
|
||||||
self.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', description, stock_uom
|
|
||||||
from `tabBOM Item`
|
|
||||||
where parent = '%s' and docstatus < 2
|
|
||||||
group by item_code
|
|
||||||
""" % (fg_qty, bom_no))
|
|
||||||
|
|
||||||
self.make_items_dict(fl_bom_sa_items)
|
|
||||||
|
|
||||||
# Update only qty remaining to be issued for production
|
|
||||||
if self.doc.purpose == 'Production Order - Material Transfer':
|
|
||||||
self.update_only_remaining_qty()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_to_stock_entry_detail(self, source_wh, target_wh, item_dict, fg_item = 0, bom_no = ''):
|
|
||||||
for d in item_dict:
|
|
||||||
se_child = addchild(self.doc, 'mtn_details', 'Stock Entry Detail', 0, self.doclist)
|
|
||||||
se_child.s_warehouse = source_wh
|
|
||||||
se_child.t_warehouse = target_wh
|
|
||||||
se_child.fg_item = fg_item
|
|
||||||
se_child.item_code = cstr(d)
|
|
||||||
se_child.description = item_dict[d][1]
|
|
||||||
se_child.uom = item_dict[d][2]
|
|
||||||
se_child.stock_uom = item_dict[d][2]
|
|
||||||
se_child.reqd_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.conversion_factor = 1.00
|
|
||||||
if fg_item: se_child.bom_no = bom_no
|
|
||||||
|
|
||||||
def get_items(self):
|
def get_items(self):
|
||||||
bom_no = self.doc.bom_no
|
self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1)
|
||||||
fg_qty = self.doc.fg_completed_qty
|
|
||||||
|
|
||||||
if self.doc.purpose.startswith('Production Order'):
|
|
||||||
if not self.doc.production_order:
|
|
||||||
webnotes.msgprint(_("Please specify Production Order"), raise_exception=1)
|
|
||||||
|
|
||||||
|
if self.doc.production_order:
|
||||||
# common validations
|
# common validations
|
||||||
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)
|
||||||
|
|
||||||
bom_no = pro_obj.doc.bom_no
|
self.doc.bom_no = pro_obj.doc.bom_no
|
||||||
fg_qty = (self.doc.purpose == 'Production Order - Update Finished Goods') \
|
self.doc.fg_completed_qty = (self.doc.purpose == "Manufacture/Repack") \
|
||||||
and flt(self.doc.fg_completed_qty) or flt(pro_obj.doc.qty)
|
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
|
||||||
|
|
||||||
self.get_raw_materials(bom_no, fg_qty, self.doc.use_multi_level_bom)
|
if self.doc.bom_no:
|
||||||
self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1)
|
if self.doc.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
|
||||||
|
"Subcontract"]:
|
||||||
|
self.get_raw_materials()
|
||||||
|
|
||||||
# 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,
|
||||||
@ -354,7 +354,8 @@ class DocType(TransactionBase):
|
|||||||
cstr(pro_obj.doc.production_item):
|
cstr(pro_obj.doc.production_item):
|
||||||
[self.doc.fg_completed_qty, pro_obj.doc.description, pro_obj.doc.stock_uom]
|
[self.doc.fg_completed_qty, pro_obj.doc.description, pro_obj.doc.stock_uom]
|
||||||
})
|
})
|
||||||
elif self.doc.bom_no:
|
elif self.doc.purpose in ["Material Receipt", "Manufacture/Repack",
|
||||||
|
"Subcontract"]:
|
||||||
item = webnotes.conn.sql("""select item, description, uom from `tabBOM`
|
item = webnotes.conn.sql("""select item, description, uom from `tabBOM`
|
||||||
where name=%s""", (self.doc.bom_no,), as_dict=1)
|
where name=%s""", (self.doc.bom_no,), as_dict=1)
|
||||||
self.add_to_stock_entry_detail(None, None, {
|
self.add_to_stock_entry_detail(None, None, {
|
||||||
@ -362,136 +363,97 @@ class DocType(TransactionBase):
|
|||||||
[self.doc.fg_completed_qty, item[0]["description"], item[0]["uom"]]
|
[self.doc.fg_completed_qty, item[0]["description"], item[0]["uom"]]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fg_item_dict = {}
|
|
||||||
if self.doc.purpose == 'Production Order - Update Finished Goods':
|
|
||||||
sw = ''
|
|
||||||
tw = cstr(pro_obj.doc.fg_warehouse)
|
|
||||||
fg_item_dict = {
|
|
||||||
cstr(pro_obj.doc.production_item) : [self.doc.fg_completed_qty,
|
|
||||||
pro_obj.doc.description, pro_obj.doc.stock_uom]
|
|
||||||
}
|
|
||||||
elif self.doc.purpose == 'Other' and self.doc.bom_no:
|
|
||||||
sw, tw = '', ''
|
|
||||||
item = sql("select item, description, uom from `tabBOM` where name = %s", self.doc.bom_no, as_dict=1)
|
|
||||||
fg_item_dict = {
|
|
||||||
item[0]['item'] : [self.doc.fg_completed_qty,
|
|
||||||
item[0]['description'], item[0]['uom']]
|
|
||||||
}
|
|
||||||
|
|
||||||
if fg_item_dict:
|
|
||||||
self.add_to_stock_entry_detail(sw, tw, fg_item_dict, fg_item = 1, bom_no = bom_no)
|
|
||||||
|
|
||||||
self.get_stock_and_rate()
|
self.get_stock_and_rate()
|
||||||
|
|
||||||
def validate_qty_as_per_stock_uom(self):
|
def get_raw_materials(self):
|
||||||
for d in getlist(self.doclist, 'mtn_details'):
|
"""
|
||||||
if flt(d.transfer_qty) <= 0:
|
get all items from flat bom except
|
||||||
msgprint("Row No #%s: Qty as per Stock UOM can not be less than \
|
child items of sub-contracted and sub assembly items
|
||||||
or equal to zero" % cint(d.idx), raise_exception=1)
|
and sub assembly items itself.
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
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
|
||||||
|
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
||||||
|
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)
|
||||||
|
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',
|
||||||
|
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))
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
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])
|
||||||
|
else:
|
||||||
|
self.item_dict[i[0]] = [flt(i[1]), cstr(i[2]), cstr(i[3])]
|
||||||
|
|
||||||
|
def update_only_remaining_qty(self):
|
||||||
|
""" Only pending raw material to be issued to shop floor """
|
||||||
|
already_issued_item = {}
|
||||||
|
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]
|
||||||
|
|
||||||
|
def add_to_stock_entry_detail(self, source_wh, target_wh, item_dict, fg_item = 0, bom_no = ''):
|
||||||
|
for d in item_dict:
|
||||||
|
se_child = addchild(self.doc, 'mtn_details', 'Stock Entry Detail', 0, self.doclist)
|
||||||
|
se_child.s_warehouse = source_wh
|
||||||
|
se_child.t_warehouse = target_wh
|
||||||
|
se_child.item_code = cstr(d)
|
||||||
|
se_child.description = item_dict[d][1]
|
||||||
|
se_child.uom = item_dict[d][2]
|
||||||
|
se_child.stock_uom = item_dict[d][2]
|
||||||
|
se_child.qty = flt(item_dict[d][0])
|
||||||
|
se_child.transfer_qty = flt(item_dict[d][0])
|
||||||
|
se_child.conversion_factor = 1.00
|
||||||
|
if fg_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({
|
||||||
'item_code' : d.item_code,
|
'item_code': d.item_code,
|
||||||
'warehouse' : wh,
|
'warehouse': wh,
|
||||||
'posting_date' : self.doc.posting_date,
|
'posting_date': self.doc.posting_date,
|
||||||
'posting_time' : self.doc.posting_time,
|
'posting_time': self.doc.posting_time,
|
||||||
'voucher_type' : 'Stock Entry',
|
'voucher_type': 'Stock Entry',
|
||||||
'voucher_no' : self.doc.name,
|
'voucher_no': self.doc.name,
|
||||||
'voucher_detail_no' : d.name,
|
'voucher_detail_no': d.name,
|
||||||
'actual_qty' : qty,
|
'actual_qty': qty,
|
||||||
'incoming_rate' : flt(d.incoming_rate) or 0,
|
'incoming_rate': flt(d.incoming_rate) or 0,
|
||||||
'stock_uom' : d.stock_uom,
|
'stock_uom': d.stock_uom,
|
||||||
'company' : self.doc.company,
|
'company': self.doc.company,
|
||||||
'is_cancelled' : (is_cancelled ==1) and 'Yes' or 'No',
|
'is_cancelled': (is_cancelled ==1) and 'Yes' or 'No',
|
||||||
'batch_no' : d.batch_no,
|
'batch_no': d.batch_no,
|
||||||
'serial_no' : d.serial_no
|
'serial_no': d.serial_no
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def update_stock_ledger(self, is_cancelled=0):
|
|
||||||
self.values = []
|
|
||||||
for d in getlist(self.doclist, 'mtn_details'):
|
|
||||||
if cstr(d.s_warehouse):
|
|
||||||
self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled)
|
|
||||||
if cstr(d.t_warehouse):
|
|
||||||
self.add_to_values(d, cstr(d.t_warehouse), flt(d.transfer_qty), is_cancelled)
|
|
||||||
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values, self.doc.amended_from and 'Yes' or 'No')
|
|
||||||
|
|
||||||
def update_production_order(self, is_submit):
|
|
||||||
if self.doc.production_order:
|
|
||||||
pro_obj = get_obj("Production Order", self.doc.production_order)
|
|
||||||
if flt(pro_obj.doc.docstatus) != 1:
|
|
||||||
msgprint("""You cannot do any transaction against
|
|
||||||
Production Order : %s, as it's not submitted"""
|
|
||||||
% (pro_obj.doc.name), raise_exception=1)
|
|
||||||
|
|
||||||
if pro_obj.doc.status == 'Stopped':
|
|
||||||
msgprint("""You cannot do any transaction against Production Order : %s,
|
|
||||||
as it's status is 'Stopped'"""% (pro_obj.doc.name), raise_exception=1)
|
|
||||||
|
|
||||||
if getdate(pro_obj.doc.posting_date) > getdate(self.doc.posting_date):
|
|
||||||
msgprint("""Posting Date of Stock Entry cannot be before Posting Date of
|
|
||||||
Production Order: %s"""% cstr(self.doc.production_order), raise_exception=1)
|
|
||||||
|
|
||||||
if self.doc.purpose == "Production Order - Update Finished Goods":
|
|
||||||
pro_obj.doc.produced_qty = flt(pro_obj.doc.produced_qty) + \
|
|
||||||
(is_submit and 1 or -1 ) * flt(self.doc.fg_completed_qty)
|
|
||||||
args = {
|
|
||||||
"item_code": pro_obj.doc.production_item,
|
|
||||||
"posting_date": self.doc.posting_date,
|
|
||||||
"planned_qty": (is_submit and -1 or 1 ) * flt(self.doc.fg_completed_qty)
|
|
||||||
}
|
|
||||||
get_obj('Warehouse', pro_obj.doc.fg_warehouse).update_bin(args)
|
|
||||||
|
|
||||||
pro_obj.doc.status = (flt(pro_obj.doc.qty)==flt(pro_obj.doc.produced_qty)) \
|
|
||||||
and 'Completed' or 'In Process'
|
|
||||||
pro_obj.doc.save()
|
|
||||||
|
|
||||||
|
|
||||||
# Create / Update Serial No
|
|
||||||
# ----------------------------------
|
|
||||||
def update_serial_no(self, is_submit):
|
|
||||||
sl_obj = get_obj('Stock Ledger')
|
|
||||||
if is_submit:
|
|
||||||
sl_obj.validate_serial_no_warehouse(self, 'mtn_details')
|
|
||||||
|
|
||||||
for d in getlist(self.doclist, 'mtn_details'):
|
|
||||||
if d.serial_no:
|
|
||||||
serial_nos = sl_obj.get_sr_no_list(d.serial_no)
|
|
||||||
for x in serial_nos:
|
|
||||||
serial_no = x.strip()
|
|
||||||
if d.s_warehouse:
|
|
||||||
sl_obj.update_serial_delivery_details(self, d, serial_no, is_submit)
|
|
||||||
if d.t_warehouse:
|
|
||||||
sl_obj.update_serial_purchase_details(self, d, serial_no, is_submit, 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
|
|
||||||
serial_doc.save()
|
|
||||||
|
|
||||||
|
|
||||||
def on_submit(self):
|
|
||||||
self.validate_qty_as_per_stock_uom()
|
|
||||||
self.update_serial_no(1)
|
|
||||||
self.update_stock_ledger(0)
|
|
||||||
# update Production Order
|
|
||||||
self.update_production_order(1)
|
|
||||||
|
|
||||||
|
|
||||||
def on_cancel(self):
|
|
||||||
self.update_serial_no(0)
|
|
||||||
self.update_stock_ledger(1)
|
|
||||||
# update Production Order
|
|
||||||
self.update_production_order(0)
|
|
||||||
|
|
||||||
|
|
||||||
def get_cust_values(self):
|
def get_cust_values(self):
|
||||||
"""fetches customer details"""
|
"""fetches customer details"""
|
||||||
if self.doc.delivery_note_no:
|
if self.doc.delivery_note_no:
|
||||||
@ -525,7 +487,8 @@ class DocType(TransactionBase):
|
|||||||
return result and result[0] or {}
|
return result and result[0] or {}
|
||||||
|
|
||||||
def get_supp_addr(self):
|
def get_supp_addr(self):
|
||||||
res = sql("select supplier_name,address from `tabSupplier` where name = '%s'"%self.doc.supplier)
|
res = sql("""select supplier_name from `tabSupplier`
|
||||||
|
where name=%s""", self.doc.supplier)
|
||||||
addr = self.get_address_text(supplier = self.doc.supplier)
|
addr = self.get_address_text(supplier = self.doc.supplier)
|
||||||
ret = {
|
ret = {
|
||||||
'supplier_name' : res and res[0][0] or '',
|
'supplier_name' : res and res[0][0] or '',
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"creation": "2012-12-17 11:42:09",
|
"creation": "2012-12-18 13:47:41",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"modified": "2012-12-17 18:19:44"
|
"modified": "2012-12-18 17:17:16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
@ -74,8 +74,8 @@
|
|||||||
"report_hide": 0
|
"report_hide": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
|
"permlevel": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -88,7 +88,7 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nSales Return\nPurchase Return\nSubcontracting\nProduction Order - Material Transfer\nProduction Order - Update Finished Goods\nOther",
|
"options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nManufacture/Repack\nSubcontract\nSales Return\nPurchase Return",
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"in_filter": 1
|
"in_filter": 1
|
||||||
},
|
},
|
||||||
@ -231,7 +231,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"depends_on": "eval:doc.purpose.startsWith(\"Production Order\")",
|
"depends_on": "eval:inList([\"Material Transfer\", \"Manufacture/Repack\"], doc.purpose)",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"search_index": 1,
|
"search_index": 1,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
@ -249,7 +249,7 @@
|
|||||||
"in_filter": 1
|
"in_filter": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.purpose.startsWith(\"Production Order\")",
|
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "BOM No",
|
"label": "BOM No",
|
||||||
"options": "BOM",
|
"options": "BOM",
|
||||||
@ -259,52 +259,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
|
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldtype": "Currency",
|
"search_index": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Manufacturing Quantity",
|
"label": "Manufacturing Quantity",
|
||||||
"oldfieldname": "fg_completed_qty",
|
"oldfieldname": "fg_completed_qty",
|
||||||
"fieldname": "fg_completed_qty",
|
"fieldname": "fg_completed_qty",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"search_index": 0,
|
"oldfieldtype": "Currency",
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"in_filter": 0
|
"in_filter": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"label": "Use Multi-Level BOM",
|
|
||||||
"fieldname": "use_multi_level_bom",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"permlevel": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"print_hide": 1,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldtype": "Button",
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"doctype": "DocField",
|
|
||||||
"label": "Get Items",
|
|
||||||
"permlevel": 0,
|
|
||||||
"fieldname": "get_items",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"search_index": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"hidden": 0,
|
|
||||||
"options": "get_items",
|
|
||||||
"report_hide": 0,
|
|
||||||
"in_filter": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "cb1",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"permlevel": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"depends_on": "eval:doc.purpose==\"Sales Return\"",
|
"depends_on": "eval:doc.purpose==\"Sales Return\"",
|
||||||
@ -324,17 +294,6 @@
|
|||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"in_filter": 0
|
"in_filter": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"print_hide": 1,
|
|
||||||
"depends_on": "eval:doc.purpose==\"Sales Return\"",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"label": "Sales Invoice No",
|
|
||||||
"options": "Sales Invoice",
|
|
||||||
"fieldname": "sales_invoice_no",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 1,
|
|
||||||
"permlevel": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"depends_on": "eval:doc.purpose==\"Purchase Return\"",
|
"depends_on": "eval:doc.purpose==\"Purchase Return\"",
|
||||||
@ -354,6 +313,51 @@
|
|||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"in_filter": 0
|
"in_filter": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "cb1",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
|
||||||
|
"default": "1",
|
||||||
|
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
|
||||||
|
"doctype": "DocField",
|
||||||
|
"label": "Use Multi-Level BOM",
|
||||||
|
"fieldname": "use_multi_level_bom",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"print_hide": 1,
|
||||||
|
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
|
||||||
|
"no_copy": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"doctype": "DocField",
|
||||||
|
"label": "Get Items",
|
||||||
|
"permlevel": 0,
|
||||||
|
"fieldname": "get_items",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"oldfieldtype": "Button",
|
||||||
|
"reqd": 0,
|
||||||
|
"hidden": 0,
|
||||||
|
"options": "get_items",
|
||||||
|
"report_hide": 0,
|
||||||
|
"in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"print_hide": 1,
|
||||||
|
"depends_on": "eval:doc.purpose==\"Sales Return\"",
|
||||||
|
"doctype": "DocField",
|
||||||
|
"label": "Sales Invoice No",
|
||||||
|
"options": "Sales Invoice",
|
||||||
|
"fieldname": "sales_invoice_no",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")",
|
"depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"creation": "2012-07-03 13:29:47",
|
"creation": "2012-12-18 13:47:41",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"modified": "2012-12-17 16:12:42"
|
"modified": "2012-12-18 17:08:52"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
@ -132,17 +132,6 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"print_hide": 1,
|
|
||||||
"oldfieldtype": "Currency",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"label": "Reqd Qty",
|
|
||||||
"oldfieldname": "reqd_qty",
|
|
||||||
"fieldname": "reqd_qty",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"permlevel": 3,
|
|
||||||
"in_filter": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
@ -191,23 +180,15 @@
|
|||||||
"in_filter": 0
|
"in_filter": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"print_hide": 1,
|
||||||
"description": "BOM No. for a Finished Good Item",
|
"description": "BOM No. for a Finished Good Item",
|
||||||
|
"no_copy": 0,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "BOM No",
|
"label": "BOM No",
|
||||||
"options": "BOM",
|
"options": "BOM",
|
||||||
"fieldname": "bom_no",
|
"fieldname": "bom_no",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
|
||||||
{
|
|
||||||
"print_hide": 1,
|
|
||||||
"oldfieldtype": "Check",
|
|
||||||
"doctype": "DocField",
|
|
||||||
"label": "FG Item",
|
|
||||||
"oldfieldname": "fg_item",
|
|
||||||
"fieldname": "fg_item",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"permlevel": 0,
|
|
||||||
"in_filter": 1
|
|
||||||
}
|
}
|
||||||
]
|
]
|
Loading…
x
Reference in New Issue
Block a user