mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-07 07:20:26 +00:00
moved directory structure
This commit is contained in:
5
production/__init__.py
Normal file
5
production/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
install_docs = [
|
||||
{"doctype":"Role", "role_name":"Production Manager", "name":"Production Manager"},
|
||||
{"doctype":"Role", "role_name":"Production User", "name":"Production User"},
|
||||
]
|
||||
1
production/doctype/__init__.py
Normal file
1
production/doctype/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
1
production/doctype/bom/__init__.py
Normal file
1
production/doctype/bom/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
164
production/doctype/bom/bom.js
Normal file
164
production/doctype/bom/bom.js
Normal file
@@ -0,0 +1,164 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// On REFRESH
|
||||
cur_frm.cscript.refresh = function(doc,dt,dn){
|
||||
if(!doc.__islocal) {
|
||||
set_field_permlevel('item',1);
|
||||
unhide_field('update_cost_as_on_today');
|
||||
} else {
|
||||
hide_field('update_cost_as_on_today');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Triggers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cur_frm.cscript.item = function(doc, dt, dn) {
|
||||
if (doc.item) {
|
||||
get_server_fields('get_item_detail',doc.item,'',doc,dt,dn,1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.workstation = function(doc,dt,dn) {
|
||||
var d = locals[dt][dn];
|
||||
if (d.workstation) {
|
||||
var callback = function(r, rt) {
|
||||
calculate_op_cost(doc, dt, dn);
|
||||
calculate_total(doc);
|
||||
}
|
||||
get_server_fields('get_workstation_details',d.workstation,'bom_operations',doc,dt,dn,1, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.hour_rate = function(doc, dt, dn) {
|
||||
calculate_op_cost(doc, dt, dn);
|
||||
calculate_total(doc);
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.time_in_mins = cur_frm.cscript.hour_rate;
|
||||
|
||||
|
||||
cur_frm.cscript.item_code = function(doc,dt,dn) {
|
||||
get_bom_material_detail(doc, dt, dn);
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.bom_no = function(doc,dt,dn) {
|
||||
get_bom_material_detail(doc, dt, dn);
|
||||
}
|
||||
|
||||
|
||||
var get_bom_material_detail= function(doc,dt,dn) {
|
||||
var d = locals[dt][dn];
|
||||
var callback = function(doc, dt, dn) {
|
||||
calculate_rm_cost(doc, dt, dn);
|
||||
calculate_total(doc);
|
||||
}
|
||||
|
||||
var bom_no = (d.bom_no!=null) ? d.bom_no:''
|
||||
if (d.item_code) {
|
||||
arg = {'item_code': d.item_code, 'bom_no': bom_no, 'qty': d.qty};
|
||||
get_server_fields('get_bom_material_detail', JSON.stringify(arg), 'bom_materials', doc, dt, dn, 1, callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.qty = function(doc, dt, dn) {
|
||||
calculate_rm_cost(doc, dt, dn);
|
||||
calculate_total(doc);
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.rate = cur_frm.cscript.qty;
|
||||
|
||||
|
||||
cur_frm.cscript.is_default = function(doc, dt, dn) {
|
||||
if (doc.docstatus == 1)
|
||||
$c_obj(make_doclist(dt, dn), 'manage_default_bom', '', '');
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.is_active = function(doc, dt, dn) {
|
||||
if (!doc.__islocal)
|
||||
$c_obj(make_doclist(dt, dn), 'manage_active_bom', '', '');
|
||||
}
|
||||
|
||||
|
||||
// Calculate Operating Cost
|
||||
var calculate_op_cost = function(doc, dt, dn) {
|
||||
var op = getchildren('BOM Operation', doc.name, 'bom_operations');
|
||||
total_op_cost = 0;
|
||||
for(var i=0;i<op.length;i++) {
|
||||
op_cost = flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60;
|
||||
set_multiple('BOM Operation',op[i].name, {'operating_cost': op_cost}, 'bom_operations');
|
||||
total_op_cost += op_cost;
|
||||
}
|
||||
doc.operating_cost = total_op_cost;
|
||||
refresh_field('operating_cost');
|
||||
}
|
||||
|
||||
|
||||
// Calculate Raw Material Cost
|
||||
var calculate_rm_cost = function(doc, dt, dn) {
|
||||
var rm = getchildren('BOM Item', doc.name, 'bom_materials');
|
||||
total_rm_cost = 0;
|
||||
for(var i=0;i<rm.length;i++) {
|
||||
amt = flt(rm[i].rate) * flt(rm[i].qty);
|
||||
set_multiple('BOM Item',rm[i].name, {'amount': amt}, 'bom_materials');
|
||||
set_multiple('BOM Item',rm[i].name, {'qty_consumed_per_unit': flt(rm[i].qty)/flt(doc.quantity)}, 'bom_materials');
|
||||
total_rm_cost += amt;
|
||||
}
|
||||
doc.raw_material_cost = total_rm_cost;
|
||||
refresh_field('raw_material_cost');
|
||||
}
|
||||
|
||||
|
||||
// Calculate Total Cost
|
||||
var calculate_total = function(doc) {
|
||||
doc.total_cost = flt(doc.raw_material_cost) + flt(doc.operating_cost);
|
||||
refresh_field('total_cost');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get Query
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
cur_frm.fields_dict['item'].get_query = function(doc) {
|
||||
return 'SELECT DISTINCT `tabItem`.`name`, `tabItem`.description FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` = "0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.`%(key)s` like "%s" ORDER BY `tabItem`.`name` LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
||||
return 'SELECT `tabProject`.name FROM `tabProject` WHERE `tabProject`.status = "Open" AND `tabProject`.name LIKE "%s" ORDER BY `tabProject`.name ASC LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['bom_materials'].grid.get_field('item_code').get_query = function(doc) {
|
||||
return 'SELECT DISTINCT `tabItem`.`name`, `tabItem`.description FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` = "0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.`%(key)s` like "%s" ORDER BY `tabItem`.`name` LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['bom_materials'].grid.get_field('bom_no').get_query = function(doc) {
|
||||
var d = locals[this.doctype][this.docname];
|
||||
return 'SELECT DISTINCT `tabBOM`.`name`, `tabBOM`.`remarks` FROM `tabBOM` WHERE `tabBOM`.`item` = "' + d.item_code + '" AND `tabBOM`.`is_active` = "Yes" AND `tabBOM`.docstatus = 1 AND `tabBOM`.`name` like "%s" ORDER BY `tabBOM`.`name` LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.cscript.validate = function(doc, dt, dn) {
|
||||
calculate_op_cost(doc, dt, dn);
|
||||
calculate_rm_cost(doc, dt, dn);
|
||||
calculate_total(doc);
|
||||
}
|
||||
400
production/doctype/bom/bom.py
Normal file
400
production/doctype/bom/bom.py
Normal file
@@ -0,0 +1,400 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint, cstr, flt, get_defaults, getdate, now, nowdate
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def autoname(self):
|
||||
last_name = sql("select max(name) from `tabBOM` where name like 'BOM/%s/%%'" % self.doc.item)
|
||||
if last_name:
|
||||
idx = cint(cstr(last_name[0][0]).split('/')[-1]) + 1
|
||||
else:
|
||||
idx = 1
|
||||
self.doc.name = 'BOM/' + self.doc.item + ('/%.3i' % idx)
|
||||
|
||||
|
||||
def get_item_det(self, item_code):
|
||||
item = sql("""select name, is_asset_item, is_purchase_item, docstatus, is_sub_contracted_item,
|
||||
description, stock_uom, default_bom, last_purchase_rate, standard_rate, is_manufactured_item from `tabItem`
|
||||
where item_code = %s""", item_code, as_dict = 1)
|
||||
|
||||
return item
|
||||
|
||||
|
||||
def get_item_detail(self, item_code):
|
||||
""" Get stock uom and description for finished good item"""
|
||||
|
||||
item = self.get_item_det(item_code)
|
||||
ret={
|
||||
'description' : item and item[0]['description'] or '',
|
||||
'uom' : item and item[0]['stock_uom'] or ''
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
def get_workstation_details(self,workstation):
|
||||
""" Fetch hour rate from workstation master"""
|
||||
|
||||
ws = sql("select hour_rate from `tabWorkstation` where name = %s",workstation , as_dict = 1)
|
||||
ret = {
|
||||
'hour_rate' : ws and flt(ws[0]['hour_rate']) or '',
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
def validate_rm_item(self, item):
|
||||
""" Validate raw material items"""
|
||||
|
||||
if item[0]['name'] == self.doc.item:
|
||||
msgprint(" Item_code: "+item[0]['name']+" in materials tab cannot be same as FG Item in BOM := " +cstr(self.doc.name), raise_exception=1)
|
||||
|
||||
if item and item[0]['is_asset_item'] == 'Yes':
|
||||
msgprint("Sorry!!! Item " + item[0]['name'] + " is an Asset of the company. Entered in BOM => " + cstr(self.doc.name), raise_exception = 1)
|
||||
|
||||
if not item or item[0]['docstatus'] == 2:
|
||||
msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1)
|
||||
|
||||
|
||||
|
||||
def get_bom_material_detail(self, arg):
|
||||
""" Get raw material details like uom, desc and rate"""
|
||||
|
||||
arg = eval(arg)
|
||||
item = self.get_item_det(arg['item_code'])
|
||||
self.validate_rm_item(item)
|
||||
|
||||
arg['bom_no'] = arg['bom_no'] or item and cstr(item[0]['default_bom']) or ''
|
||||
arg.update(item[0])
|
||||
|
||||
rate = self.get_rm_rate(arg)
|
||||
ret_item = {
|
||||
'description' : item and arg['description'] or '',
|
||||
'stock_uom' : item and arg['stock_uom'] or '',
|
||||
'bom_no' : arg['bom_no'],
|
||||
'rate' : rate
|
||||
}
|
||||
return ret_item
|
||||
|
||||
|
||||
def get_rm_rate(self, arg):
|
||||
""" Get raw material rate as per selected method, if bom exists takes bom cost """
|
||||
|
||||
if arg['bom_no']:
|
||||
bom = sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
|
||||
where is_active = 'Yes' and name = %s""", arg['bom_no'], as_dict=1)
|
||||
rate = bom and bom[0]['unit_cost'] or 0
|
||||
elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'):
|
||||
if self.doc.rm_cost_as_per == 'Valuation Rate':
|
||||
rate = self.get_valuation_rate(arg)
|
||||
elif self.doc.rm_cost_as_per == 'Last Purchase Rate':
|
||||
rate = arg['last_purchase_rate']
|
||||
elif self.doc.rm_cost_as_per == 'Standard Rate':
|
||||
rate = arg['standard_rate']
|
||||
|
||||
return rate
|
||||
|
||||
|
||||
|
||||
def get_valuation_rate(self, arg):
|
||||
""" Get average valuation rate of relevant warehouses
|
||||
as per valuation method (MAR/FIFO)
|
||||
as on costing date
|
||||
"""
|
||||
|
||||
dt = self.doc.costing_date or nowdate()
|
||||
time = self.doc.costing_date == nowdate() and now().split()[1] or '23:59'
|
||||
warehouse = sql("select warehouse from `tabBin` where item_code = %s", arg['item_code'])
|
||||
rate = []
|
||||
for wh in warehouse:
|
||||
r = get_obj('Valuation Control').get_incoming_rate(dt, time, arg['item_code'], wh[0], qty = arg.get('qty', 0))
|
||||
if r:
|
||||
rate.append(r)
|
||||
|
||||
return rate and flt(sum(rate))/len(rate) or 0
|
||||
|
||||
|
||||
|
||||
def manage_default_bom(self):
|
||||
""" Uncheck others if current one is selected as default, update default bom in item master"""
|
||||
|
||||
if self.doc.is_default and self.doc.is_active == 'Yes':
|
||||
sql("update `tabBOM` set is_default = 0 where name != %s and item=%s", (self.doc.name, self.doc.item))
|
||||
|
||||
# update default bom in Item Master
|
||||
sql("update `tabItem` set default_bom = %s where name = %s", (self.doc.name, self.doc.item))
|
||||
else:
|
||||
sql("update `tabItem` set default_bom = '' where name = %s and default_bom = %s", (self.doc.item, self.doc.name))
|
||||
|
||||
|
||||
|
||||
def manage_active_bom(self):
|
||||
""" Manage active/inactive """
|
||||
if self.doc.is_active == 'Yes':
|
||||
self.validate()
|
||||
else:
|
||||
self.check_active_parent_boms()
|
||||
|
||||
|
||||
|
||||
def check_active_parent_boms(self):
|
||||
""" Check parent BOM before making it inactive """
|
||||
act_pbom = sql("""select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2
|
||||
where t1.bom_no =%s and t2.name = t1.parent and t2.is_active = 'Yes'
|
||||
and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
|
||||
if act_pbom and act_pbom[0][0]:
|
||||
msgprint("""Sorry cannot inactivate as BOM: %s is child
|
||||
of one or many other active parent BOMs""" % self.doc.name, raise_exception=1)
|
||||
|
||||
|
||||
|
||||
def calculate_cost(self):
|
||||
"""Calculate bom totals"""
|
||||
self.doc.costing_date = nowdate()
|
||||
self.calculate_op_cost()
|
||||
self.calculate_rm_cost()
|
||||
self.doc.total_cost = self.doc.raw_material_cost + self.doc.operating_cost
|
||||
self.doc.modified = now()
|
||||
self.doc.save()
|
||||
|
||||
self.update_flat_bom_engine(is_submit = self.doc.docstatus)
|
||||
|
||||
|
||||
|
||||
def calculate_op_cost(self):
|
||||
"""Update workstation rate and calculates totals"""
|
||||
total_op_cost = 0
|
||||
for d in getlist(self.doclist, 'bom_operations'):
|
||||
hour_rate = sql("select hour_rate from `tabWorkstation` where name = %s", cstr(d.workstation))
|
||||
d.hour_rate = hour_rate and flt(hour_rate[0][0]) or 0
|
||||
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60
|
||||
d.save()
|
||||
total_op_cost += d.operating_cost
|
||||
self.doc.operating_cost = total_op_cost
|
||||
|
||||
|
||||
|
||||
def calculate_rm_cost(self):
|
||||
"""Fetch RM rate as per today's valuation rate and calculate totals"""
|
||||
total_rm_cost = 0
|
||||
for d in getlist(self.doclist, 'bom_materials'):
|
||||
#if self.doc.rm_cost_as_per == 'Valuation Rate':
|
||||
arg = {'item_code': d.item_code, 'qty': d.qty, 'bom_no': d.bom_no}
|
||||
ret = self.get_bom_material_detail(cstr(arg))
|
||||
for k in ret:
|
||||
d.fields[k] = ret[k]
|
||||
|
||||
d.amount = flt(d.rate) * flt(d.qty)
|
||||
d.save()
|
||||
total_rm_cost += d.amount
|
||||
self.doc.raw_material_cost = total_rm_cost
|
||||
|
||||
|
||||
|
||||
def validate_main_item(self):
|
||||
""" Validate main FG item"""
|
||||
item = self.get_item_det(self.doc.item)
|
||||
if not item:
|
||||
msgprint("Item %s does not exists in the system or expired." % self.doc.item, raise_exception = 1)
|
||||
|
||||
elif item[0]['is_manufactured_item'] != 'Yes' and item[0]['is_sub_contracted_item'] != 'Yes':
|
||||
msgprint("""As Item: %s is not a manufactured / sub-contracted item,
|
||||
you can not make BOM for it""" % self.doc.item, raise_exception = 1)
|
||||
|
||||
|
||||
|
||||
def validate_operations(self):
|
||||
""" Check duplicate operation no"""
|
||||
self.op = []
|
||||
for d in getlist(self.doclist, 'bom_operations'):
|
||||
if cstr(d.operation_no) in self.op:
|
||||
msgprint("Operation no: %s is repeated in Operations Table"% d.operation_no, raise_exception=1)
|
||||
else:
|
||||
# add operation in op list
|
||||
self.op.append(cstr(d.operation_no))
|
||||
|
||||
|
||||
|
||||
def validate_materials(self):
|
||||
""" Validate raw material entries """
|
||||
check_list = []
|
||||
for m in getlist(self.doclist, 'bom_materials'):
|
||||
# check if operation no not in op table
|
||||
if m.operation_no not in self.op:
|
||||
msgprint("""Operation no: %s against item: %s at row no: %s is not present
|
||||
at Operations table"""% (m.operation_no, m.item_code, m.idx), raise_exception = 1)
|
||||
|
||||
item = self.get_item_det(m.item_code)
|
||||
if item[0]['is_manufactured_item'] == 'Yes' or item[0]['is_sub_contracted_item'] == 'Yes':
|
||||
if not m.bom_no:
|
||||
msgprint("Please enter BOM No aginst item: %s at row no: %s"% (m.item_code, m.idx), raise_exception=1)
|
||||
else:
|
||||
self.validate_bom_no(m.item_code, m.bom_no, m.idx)
|
||||
|
||||
elif m.bom_no:
|
||||
msgprint("""As Item %s is not a manufactured / sub-contracted item,
|
||||
you can enter BOM against it (Row No: %s)."""% (m.item_code, m.idx), raise_excepiton = 1)
|
||||
|
||||
if flt(m.qty) <= 0:
|
||||
msgprint("Please enter qty against raw material: %s at row no: %s"% (m.item_code, m.idx), raise_exception = 1)
|
||||
|
||||
self.check_if_item_repeated(m.item_code, m.operation_no, check_list)
|
||||
|
||||
|
||||
|
||||
def validate_bom_no(self, item, bom_no, idx):
|
||||
"""Validate BOM No of sub-contracted items"""
|
||||
bom = sql("""select name from `tabBOM` where name = %s and item = %s
|
||||
and ifnull(is_active, 'No') = 'Yes' and docstatus < 2 """, (bom_no, item), as_dict =1)
|
||||
if not bom:
|
||||
msgprint("""Incorrect BOM No: %s against item: %s at row no: %s.
|
||||
It may be inactive or cancelled or for some other item."""% (bom_no, item, idx), raise_exception = 1)
|
||||
|
||||
|
||||
|
||||
def check_if_item_repeated(self, item, op, check_list):
|
||||
if [cstr(item), cstr(op)] in check_list:
|
||||
msgprint("Item %s has been entered twice against same operation" % item, raise_exception = 1)
|
||||
else:
|
||||
check_list.append([cstr(item), cstr(op)])
|
||||
|
||||
|
||||
|
||||
#----- Document on Save function------
|
||||
def validate(self):
|
||||
self.validate_main_item()
|
||||
self.validate_operations()
|
||||
self.validate_materials()
|
||||
|
||||
|
||||
|
||||
def check_recursion(self):
|
||||
""" Check whether reqursion occurs in any bom"""
|
||||
|
||||
check_list = [['parent', 'bom_no', 'parent'], ['bom_no', 'parent', 'child']]
|
||||
for d in check_list:
|
||||
bom_list, count = [self.doc.name], 0
|
||||
while (len(bom_list) > count ):
|
||||
boms = sql(" select %s from `tabBOM Item` where %s = '%s' " % (d[0], d[1], cstr(bom_list[count])))
|
||||
count = count + 1
|
||||
for b in boms:
|
||||
if b[0] == self.doc.name:
|
||||
msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'.
|
||||
""" % (cstr(b), cstr(d[2]), self.doc.name), raise_exception = 1)
|
||||
if b[0]:
|
||||
bom_list.append(b[0])
|
||||
|
||||
|
||||
|
||||
def on_update(self):
|
||||
self.check_recursion()
|
||||
|
||||
|
||||
|
||||
def add_to_flat_bom_detail(self, is_submit = 0):
|
||||
"Add items to Flat BOM table"
|
||||
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
|
||||
for d in self.cur_flat_bom_items:
|
||||
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', 1, self.doclist)
|
||||
for i in d.keys():
|
||||
ch.fields[i] = d[i]
|
||||
ch.docstatus = is_submit
|
||||
ch.save(1)
|
||||
self.doc.save()
|
||||
|
||||
|
||||
|
||||
def get_child_flat_bom_items(self, bom_no, qty):
|
||||
""" Add all items from Flat BOM of child BOM"""
|
||||
|
||||
child_fb_items = sql("""select item_code, description, stock_uom, qty, rate, amount, parent_bom, mat_detail_no, qty_consumed_per_unit
|
||||
from `tabBOM Explosion Item` where parent = '%s' and docstatus = 1""" % bom_no, as_dict = 1)
|
||||
for d in child_fb_items:
|
||||
self.cur_flat_bom_items.append({
|
||||
'item_code' : d['item_code'],
|
||||
'description' : d['description'],
|
||||
'stock_uom' : d['stock_uom'],
|
||||
'qty' : flt(d['qty_consumed_per_unit'])*qty,
|
||||
'rate' : flt(d['rate']),
|
||||
'amount' : flt(d['amount']),
|
||||
'parent_bom' : d['parent_bom'],
|
||||
'mat_detail_no' : d['mat_detail_no'],
|
||||
'qty_consumed_per_unit' : flt(d['qty_consumed_per_unit'])*qty/flt(self.doc.quantity)
|
||||
|
||||
})
|
||||
|
||||
|
||||
# Get Current Flat BOM Items
|
||||
# -----------------------------
|
||||
def get_current_flat_bom_items(self):
|
||||
""" Get all raw materials including items from child bom"""
|
||||
self.cur_flat_bom_items = []
|
||||
for d in getlist(self.doclist, 'bom_materials'):
|
||||
self.cur_flat_bom_items.append({
|
||||
'item_code' : d.item_code,
|
||||
'description' : d.description,
|
||||
'stock_uom' : d.stock_uom,
|
||||
'qty' : flt(d.qty),
|
||||
'rate' : flt(d.rate),
|
||||
'amount' : flt(d.amount),
|
||||
'parent_bom' : d.parent, #item and item[0][0]=='No' and d.bom_no or d.parent,
|
||||
'mat_detail_no' : d.name,
|
||||
'qty_consumed_per_unit' : flt(d.qty_consumed_per_unit)
|
||||
})
|
||||
if d.bom_no:
|
||||
self.get_child_flat_bom_items(d.bom_no, d.qty)
|
||||
|
||||
|
||||
def update_flat_bom_engine(self, is_submit = 0):
|
||||
""" Update Flat BOM, following will be correct data"""
|
||||
self.get_current_flat_bom_items()
|
||||
self.add_to_flat_bom_detail(is_submit)
|
||||
|
||||
|
||||
def get_parent_bom_list(self, bom_no):
|
||||
p_bom = sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
|
||||
return p_bom and [i[0] for i in p_bom] or []
|
||||
|
||||
|
||||
def on_submit(self):
|
||||
self.manage_default_bom()
|
||||
self.update_flat_bom_engine(1)
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
# check if used in any other bom
|
||||
par = sql("""select t1.parent from `tabBOM Item` t1, `tabBOM` t2
|
||||
where t1.parent = t2.name and t1.bom_no = %s and t1.docstatus = 1 and t2.is_active = 'Yes'""", self.doc.name)
|
||||
if par:
|
||||
msgprint("BOM can not be cancelled, as it is a child item in following active BOM %s"% [d[0] for d in par])
|
||||
raise Exception
|
||||
462
production/doctype/bom/bom.txt
Normal file
462
production/doctype/bom/bom.txt
Normal file
@@ -0,0 +1,462 @@
|
||||
# DocType, BOM
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:02',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:45:46',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1326963484',
|
||||
'allow_attach': 0,
|
||||
'allow_copy': 0,
|
||||
'allow_email': 0,
|
||||
'allow_print': 0,
|
||||
'allow_rename': 0,
|
||||
'allow_trash': 1,
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'document_type': u'Master',
|
||||
'hide_heading': 0,
|
||||
'hide_toolbar': 0,
|
||||
'in_create': 0,
|
||||
'is_submittable': 1,
|
||||
'issingle': 0,
|
||||
'istable': 0,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'read_only': 0,
|
||||
'search_fields': u'item',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'subject': u'%(item)s',
|
||||
'version': 196
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, BOM
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'BOM'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'System Manager',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production Manager',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'Production Manager'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production User',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'Production User'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'oldfieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Select the item code for which Bill of Material is being created',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'item',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'Item',
|
||||
'oldfieldname': u'item',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'search_index': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Total quantity of items for which raw materials required and operations done will be defined',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'quantity',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Quantity',
|
||||
'oldfieldname': u'quantity',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'uom',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'UOM',
|
||||
'options': u'link:UOM',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 0,
|
||||
'width': u'300px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break1',
|
||||
'fieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'Select name of the project if BOM need to be created against any project',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'project_name',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'Project Name',
|
||||
'oldfieldname': u'project_name',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Project',
|
||||
'permlevel': 0,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_active',
|
||||
'fieldtype': u'Select',
|
||||
'hidden': 0,
|
||||
'label': u'Is Active',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'is_active',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'\nYes\nNo',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_default',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Is Default',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'is_default',
|
||||
'oldfieldtype': u'Check',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'maintained_by',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Maintained By',
|
||||
'oldfieldname': u'maintained_by',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'remarks',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Remarks',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'remarks',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'operations',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Operations',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Specify the operations, operating cost and give a unique Operation no to your operations.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'bom_operations',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'BOM Operations',
|
||||
'oldfieldname': u'bom_operations',
|
||||
'oldfieldtype': u'Table',
|
||||
'options': u'BOM Operation',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'materials',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Materials',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Enter the raw materials required to manufacture the BOM item. Specify the operation no as entered in the previous tab which will be performed on the raw materials entered.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'bom_materials',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'BOM Item',
|
||||
'oldfieldname': u'bom_materials',
|
||||
'oldfieldtype': u'Table',
|
||||
'options': u'BOM Item',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'costing',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Costing',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break2',
|
||||
'fieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'rm_cost_as_per',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'Consider Raw Material Cost As Per',
|
||||
'options': u'Valuation Rate\nLast Purchase Rate\nStandard Rate',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'costing_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Costing Date',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'update_cost_as_on_today',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Update Cost as on today',
|
||||
'options': u'calculate_cost',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break3',
|
||||
'fieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'raw_material_cost',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Raw Material Cost',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'operating_cost',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Operating Cost',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'total_cost',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Total Cost',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'section_break0',
|
||||
'fieldtype': u'Section Break',
|
||||
'hidden': 1,
|
||||
'options': u'Simple',
|
||||
'permlevel': 0,
|
||||
'print_hide': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'No Toolbar',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'flat_bom_details',
|
||||
'fieldtype': u'Table',
|
||||
'hidden': 1,
|
||||
'label': u'BOM Explosion Item',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'flat_bom_details',
|
||||
'oldfieldtype': u'Table',
|
||||
'options': u'BOM Explosion Item',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'trash_reason',
|
||||
'fieldtype': u'Small Text',
|
||||
'hidden': 1,
|
||||
'label': u'Trash Reason',
|
||||
'oldfieldname': u'trash_reason',
|
||||
'oldfieldtype': u'Small Text',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'depends_on': u'eval:doc.amended_from',
|
||||
'description': u'The date at which current entry is corrected in the system.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amendment_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Amendment Date',
|
||||
'no_copy': 1,
|
||||
'permlevel': 0,
|
||||
'print_hide': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amended_from',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Amended From',
|
||||
'no_copy': 1,
|
||||
'options': u'Sales Invoice',
|
||||
'permlevel': 1,
|
||||
'print_hide': 1
|
||||
}
|
||||
]
|
||||
48
production/doctype/bom/bom_list.js
Normal file
48
production/doctype/bom/bom_list.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// render
|
||||
wn.doclistviews['BOM'] = wn.views.ListView.extend({
|
||||
init: function(d) {
|
||||
this._super(d);
|
||||
this.fields = this.fields.concat([
|
||||
'`tabBOM`.item',
|
||||
'`tabBOM`.uom',
|
||||
'IFNULL(`tabBOM`.quantity, 0) as quantity',
|
||||
'`tabBOM`.is_active',
|
||||
'`tabBOM`.costing_date',
|
||||
'`tabBOM`.total_cost',
|
||||
'`tabBOM`.description',
|
||||
]);
|
||||
this.stats = this.stats.concat(['company']);
|
||||
},
|
||||
|
||||
prepare_data: function(data) {
|
||||
this._super(data);
|
||||
data.costing_date = wn.datetime.str_to_user(data.costing_date);
|
||||
data.description = (data.is_active === 'Yes' ? '' : '[Inactive] ') + data.description;
|
||||
},
|
||||
|
||||
columns: [
|
||||
{width: '3%', content: 'check'},
|
||||
{width: '3%', content: 'docstatus'},
|
||||
{width: '15%', content: 'name'},
|
||||
{width: '15%', content: 'item'},
|
||||
{width: '23%', content: 'description+tags'},
|
||||
{
|
||||
width: '12%',
|
||||
content: function(parent, data) {
|
||||
$(parent).html(data.quantity + ' ' + data.uom)
|
||||
},
|
||||
css: {'text-align':'right'},
|
||||
},
|
||||
{
|
||||
width: '20%',
|
||||
content: function(parent, data) {
|
||||
$(parent).html(sys_defaults.currency + " "
|
||||
+ fmt_money(data.total_cost));
|
||||
},
|
||||
css: {'text-align': 'right'},
|
||||
},
|
||||
{width: '12%', content:'costing_date', css: {
|
||||
'text-align': 'right', 'color':'#777'
|
||||
}},
|
||||
]
|
||||
});
|
||||
1
production/doctype/bom_control/__init__.py
Normal file
1
production/doctype/bom_control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
122
production/doctype/bom_control/bom_control.py
Normal file
122
production/doctype/bom_control/bom_control.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import cint, flt
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
|
||||
|
||||
def get_item_group(self):
|
||||
ret = sql("select name from `tabItem Group` ")
|
||||
item_group = []
|
||||
for r in ret:
|
||||
item =sql("select t1.name from `tabItem` t1, `tabBOM` t2 where t2.item = t1.name and t1.item_group = '%s' " % (r[0]))
|
||||
if item and item[0][0]:
|
||||
item_group.append(r[0])
|
||||
return '~~~'.join([r for r in item_group])
|
||||
|
||||
|
||||
|
||||
def get_item_code(self,item_group):
|
||||
""" here BOM docstatus = 1 and is_active ='yes' condition is not given because some bom
|
||||
is under construction that is it is still in saved mode and they want see till where they have reach.
|
||||
"""
|
||||
ret = sql("select distinct t1.name from `tabItem` t1, `tabBOM` t2 where t2.item = t1.name and t1.item_group = '%s' " % (item_group))
|
||||
return '~~~'.join([r[0] for r in ret])
|
||||
|
||||
|
||||
|
||||
def get_bom_no(self,item_code):
|
||||
ret = sql("select name from `tabBOM` where item = '%s' " % (item_code))
|
||||
return '~~~'.join([r[0] for r in ret])
|
||||
|
||||
|
||||
|
||||
def get_operations(self,bom_no):
|
||||
ret = sql("select operation_no,opn_description,workstation,hour_rate,time_in_mins from `tabBOM Operation` where parent = %s", bom_no, as_dict = 1)
|
||||
cost = sql("select dir_mat_as_per_mar , operating_cost , cost_as_per_mar from `tabBOM` where name = %s", bom_no, as_dict = 1)
|
||||
|
||||
# Validate the BOM ENTRIES
|
||||
reply = []
|
||||
|
||||
if ret:
|
||||
for r in ret:
|
||||
reply.append(['operation',cint(r['operation_no']), r['opn_description'] or '','%s'% bom_no,r['workstation'],flt(r['hour_rate']),flt(r['time_in_mins']),0,0,0])
|
||||
|
||||
reply[0][7]= flt(cost[0]['dir_mat_as_per_mar'])
|
||||
reply[0][8]=flt(cost[0]['operating_cost'])
|
||||
reply[0][9]=flt(cost[0]['cost_as_per_mar'])
|
||||
return reply
|
||||
|
||||
|
||||
|
||||
def get_item_bom(self,data):
|
||||
data = eval(data)
|
||||
reply = []
|
||||
ret = sql("select item_code,description,bom_no,qty,scrap,stock_uom,value_as_per_mar,moving_avg_rate from `tabBOM Item` where parent = '%s' and operation_no = '%s'" % (data['bom_no'],data['op_no']), as_dict =1 )
|
||||
|
||||
for r in ret:
|
||||
item = sql("select is_manufactured_item, is_sub_contracted_item from `tabItem` where name = '%s'" % r['item_code'], as_dict=1)
|
||||
if not item[0]['is_manufactured_item'] == 'Yes' and not item[0]['is_sub_contracted_item'] =='Yes':
|
||||
#if item is not manufactured or it is not sub-contracted
|
||||
reply.append([ 'item_bom', r['item_code'] or '', r['description'] or '', r['bom_no'] or '', flt(r['qty']) or 0, r['stock_uom'] or '', flt(r['scrap']) or 0, flt(r['moving_avg_rate']) or 0, 1])
|
||||
else:
|
||||
# if it is manufactured or sub_contracted this will be considered(here item can be purchase item)
|
||||
reply.append([ 'item_bom', r['item_code'] or '', r['description'] or '', r['bom_no'] or '', flt(r['qty']) or 0, r['stock_uom'] or '', flt(r['scrap']) or 0, flt(r['value_as_per_mar']) or 0, 0])
|
||||
return reply
|
||||
|
||||
|
||||
|
||||
#------------- Wrapper Code --------------
|
||||
def calculate_cost(self, bom_no):
|
||||
main_bom_list = get_obj('Production Control').traverse_bom_tree( bom_no = bom_no, qty = 1, calculate_cost = 1)
|
||||
main_bom_list.reverse()
|
||||
for bom in main_bom_list:
|
||||
bom_obj = get_obj('BOM', bom, with_children = 1)
|
||||
bom_obj.calculate_cost()
|
||||
return 'calculated'
|
||||
|
||||
|
||||
|
||||
def get_bom_tree_list(self,args):
|
||||
arg = eval(args)
|
||||
i =[]
|
||||
for a in sql("select t1.name from `tabBOM` t1, `tabItem` t2 where t2.item_group like '%s' and t1.item like '%s'"%(arg['item_group'] +'%',arg['item_code'] + '%')):
|
||||
if a[0] not in i:
|
||||
i.append(a[0])
|
||||
return i
|
||||
31
production/doctype/bom_control/bom_control.txt
Normal file
31
production/doctype/bom_control/bom_control.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
# DocType, BOM Control
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:02',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:02',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'issingle': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 108
|
||||
},
|
||||
|
||||
# DocType, BOM Control
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'BOM Control'
|
||||
}
|
||||
]
|
||||
1
production/doctype/bom_explosion_item/__init__.py
Normal file
1
production/doctype/bom_explosion_item/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
138
production/doctype/bom_explosion_item/bom_explosion_item.txt
Normal file
138
production/doctype/bom_explosion_item/bom_explosion_item.txt
Normal file
@@ -0,0 +1,138 @@
|
||||
# DocType, BOM Explosion Item
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:03',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:03',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'jai@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'autoname': u'FBD/.######',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'read_only': 0,
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 24
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM Explosion Item',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocType, BOM Explosion Item
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'BOM Explosion Item'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'item_code',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Item Code',
|
||||
'oldfieldname': u'item_code',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'width': u'300px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'qty',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Qty',
|
||||
'oldfieldname': u'qty',
|
||||
'oldfieldtype': u'Currency'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'rate',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Rate',
|
||||
'oldfieldname': u'standard_rate',
|
||||
'oldfieldtype': u'Currency'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amount',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Amount',
|
||||
'oldfieldname': u'amount_as_per_sr',
|
||||
'oldfieldtype': u'Currency'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'stock_uom',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Stock UOM',
|
||||
'oldfieldname': u'stock_uom',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'UOM'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'parent_bom',
|
||||
'fieldtype': u'Link',
|
||||
'hidden': 0,
|
||||
'label': u'Parent BOM',
|
||||
'oldfieldname': u'parent_bom',
|
||||
'oldfieldtype': u'Link',
|
||||
'width': u'250px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'mat_detail_no',
|
||||
'fieldtype': u'Data',
|
||||
'hidden': 1,
|
||||
'label': u'Mat Detail No'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'qty_consumed_per_unit',
|
||||
'fieldtype': u'Float',
|
||||
'hidden': 0,
|
||||
'label': u'Qty Consumed Per Unit',
|
||||
'no_copy': 0
|
||||
}
|
||||
]
|
||||
1
production/doctype/bom_item/__init__.py
Normal file
1
production/doctype/bom_item/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
194
production/doctype/bom_item/bom_item.txt
Normal file
194
production/doctype/bom_item/bom_item.txt
Normal file
@@ -0,0 +1,194 @@
|
||||
# DocType, BOM Item
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:02',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:02',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 27
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM Item',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM Item',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocType, BOM Item
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'BOM Item'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'operation_no',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Operation No',
|
||||
'oldfieldname': u'operation_no',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'item_code',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'Item Code',
|
||||
'oldfieldname': u'item_code',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'search_index': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'bom_no',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'BOM No',
|
||||
'oldfieldname': u'bom_no',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'BOM',
|
||||
'permlevel': 0,
|
||||
'reqd': 0,
|
||||
'search_index': 1,
|
||||
'trigger': u'Client',
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'qty',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Qty',
|
||||
'oldfieldname': u'qty',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'stock_uom',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Stock UOM',
|
||||
'oldfieldname': u'stock_uom',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'rate',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Rate',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amount',
|
||||
'fieldtype': u'Float',
|
||||
'label': u'Amount',
|
||||
'oldfieldname': u'amount_as_per_mar',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'scrap',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Scrap %',
|
||||
'oldfieldname': u'scrap',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Item Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 0,
|
||||
'reqd': 0,
|
||||
'width': u'250px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'qty_consumed_per_unit',
|
||||
'fieldtype': u'Float',
|
||||
'hidden': 1,
|
||||
'label': u'Qty Consumed Per Unit',
|
||||
'oldfieldname': u'qty_consumed_per_unit',
|
||||
'oldfieldtype': u'Float',
|
||||
'permlevel': 1,
|
||||
'print_hide': 1
|
||||
}
|
||||
]
|
||||
1
production/doctype/bom_operation/__init__.py
Normal file
1
production/doctype/bom_operation/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
135
production/doctype/bom_operation/bom_operation.txt
Normal file
135
production/doctype/bom_operation/bom_operation.txt
Normal file
@@ -0,0 +1,135 @@
|
||||
# DocType, BOM Operation
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:02',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:02',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 8
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM Operation',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'BOM Operation',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocType, BOM Operation
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'BOM Operation'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'operation_no',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Operation No',
|
||||
'oldfieldname': u'operation_no',
|
||||
'oldfieldtype': u'Data',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'opn_description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Opn Description',
|
||||
'oldfieldname': u'opn_description',
|
||||
'oldfieldtype': u'Text',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'workstation',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Workstation',
|
||||
'oldfieldname': u'workstation',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Workstation',
|
||||
'reqd': 0,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate',
|
||||
'oldfieldname': u'hour_rate',
|
||||
'oldfieldtype': u'Currency',
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'time_in_mins',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Operation Time (mins)',
|
||||
'oldfieldname': u'time_in_mins',
|
||||
'oldfieldtype': u'Currency',
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 0,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'operating_cost',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Operating Cost',
|
||||
'oldfieldname': u'operating_cost',
|
||||
'oldfieldtype': u'Currency',
|
||||
'reqd': 0
|
||||
}
|
||||
]
|
||||
1
production/doctype/production_control/__init__.py
Normal file
1
production/doctype/production_control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
116
production/doctype/production_control/production_control.py
Normal file
116
production/doctype/production_control/production_control.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__( self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
self.pur_items = {}
|
||||
self.bom_list = []
|
||||
self.sub_assembly_items = []
|
||||
self.item_master = {}
|
||||
|
||||
def traverse_bom_tree( self, bom_no, qty, ext_pur_items = 0, ext_sub_assembly_items = 0, calculate_cost = 0, maintain_item_master = 0 ):
|
||||
count, bom_list, qty_list = 0, [bom_no], [qty]
|
||||
while (count < len(bom_list)):
|
||||
# get child items from BOM MAterial Table.
|
||||
child_items = sql("select item_code, bom_no, qty, qty_consumed_per_unit from `tabBOM Item` where parent = %s", bom_list[count], as_dict = 1)
|
||||
child_items = child_items and child_items or []
|
||||
for item in child_items:
|
||||
# Calculate qty required for FG's qty.
|
||||
item['reqd_qty'] = flt(qty) * ((count == 0) and 1 or flt(qty_list[count]) )* flt(item['qty_consumed_per_unit'])
|
||||
|
||||
# extracting Purchase Items
|
||||
if ext_pur_items and not item['bom_no']:
|
||||
self.pur_items[item['item_code']] = flt(self.pur_items.get(item['item_code'], 0)) + flt(item['reqd_qty'])
|
||||
|
||||
# For calculate cost extracting BOM Items check for duplicate boms, this optmizes the time complexity for while loop.
|
||||
if calculate_cost and item['bom_no'] and (item['bom_no'] not in bom_list):
|
||||
bom_list.append(item['bom_no'])
|
||||
qty_list.append(item['reqd_qty'])
|
||||
|
||||
# Here repeated bom are considered to calculate total qty of raw material required
|
||||
if not calculate_cost and item['bom_no']:
|
||||
bom_list.append(item['bom_no'])
|
||||
qty_list.append(item['reqd_qty'])
|
||||
|
||||
count += 1
|
||||
return bom_list
|
||||
|
||||
|
||||
|
||||
# Raise Production Order
|
||||
def create_production_order(self,company, pp_items):
|
||||
"""Create production order. Called from Production Planning Tool"""
|
||||
|
||||
default_values = {
|
||||
'posting_date' : nowdate(),
|
||||
'origin' : 'MRP',
|
||||
'wip_warehouse' : '',
|
||||
'fg_warehouse' : '',
|
||||
'status' : 'Draft',
|
||||
'company' : company,
|
||||
'fiscal_year' : get_defaults()['fiscal_year']
|
||||
}
|
||||
pro_list = []
|
||||
|
||||
for d in pp_items:
|
||||
pro_doc = Document('Production Order')
|
||||
for key in d.keys():
|
||||
pro_doc.fields[key] = d[key]
|
||||
|
||||
for key in default_values:
|
||||
pro_doc.fields[key] = default_values[key]
|
||||
|
||||
pro_doc.save(new = 1)
|
||||
pro_list.append(pro_doc.name)
|
||||
|
||||
return pro_list
|
||||
|
||||
|
||||
def update_bom(self, bom_no):
|
||||
main_bom_list = self.traverse_bom_tree(bom_no, 1)
|
||||
main_bom_list.reverse()
|
||||
# run calculate cost and get
|
||||
for bom in main_bom_list:
|
||||
if bom and bom not in self.check_bom_list:
|
||||
bom_obj = get_obj('BOM', bom, with_children = 1)
|
||||
bom_obj.doc.save()
|
||||
bom_obj.check_recursion()
|
||||
bom_obj.update_flat_bom_engine()
|
||||
bom_obj.doc.docstatus = 1
|
||||
bom_obj.doc.save()
|
||||
self.check_bom_list.append(bom)
|
||||
31
production/doctype/production_control/production_control.txt
Normal file
31
production/doctype/production_control/production_control.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
# DocType, Production Control
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:05',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:05',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'issingle': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 19
|
||||
},
|
||||
|
||||
# DocType, Production Control
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Production Control'
|
||||
}
|
||||
]
|
||||
1
production/doctype/production_order/__init__.py
Normal file
1
production/doctype/production_order/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
118
production/doctype/production_order/production_order.js
Normal file
118
production/doctype/production_order/production_order.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if (!doc.posting_date) doc.transaction_date = dateutil.obj_to_str(new Date());
|
||||
if (!doc.status) doc.status = 'Draft';
|
||||
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
|
||||
if (doc.origin != "MRP"){
|
||||
doc.origin = "Manual";
|
||||
set_field_permlevel('production_item', 0);
|
||||
set_field_permlevel('bom_no', 0);
|
||||
set_field_permlevel('consider_sa_items',0);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== Refresh ==========================================
|
||||
cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
}
|
||||
|
||||
var cfn_set_fields = function(doc, dt, dn) {
|
||||
if (doc.docstatus == 1) {
|
||||
if (doc.status != 'Stopped' && doc.status != 'Completed')
|
||||
cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Production Order']);
|
||||
else if (doc.status == 'Stopped')
|
||||
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('Transfer Material', cur_frm.cscript['Transfer Material']);
|
||||
cur_frm.add_custom_button('Backflush', cur_frm.cscript['Backflush']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================================================================================================
|
||||
|
||||
cur_frm.cscript.production_item = function(doc, dt, dn) {
|
||||
get_server_fields('get_item_detail',doc.production_item,'',doc,dt,dn,1);
|
||||
}
|
||||
|
||||
// Stop PRODUCTION ORDER
|
||||
//
|
||||
cur_frm.cscript['Stop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm("Do you really want to stop production order: " + doc.name);
|
||||
if (check) {
|
||||
$c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Stopped', function(r, rt) {cur_frm.refresh();});
|
||||
}
|
||||
}
|
||||
|
||||
// Unstop PRODUCTION ORDER
|
||||
//
|
||||
cur_frm.cscript['Unstop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm("Do really want to unstop production order: " + doc.name);
|
||||
if (check)
|
||||
$c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Transfer Material'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
cur_frm.cscript.make_se(doc, process = 'Material Transfer');
|
||||
}
|
||||
|
||||
cur_frm.cscript['Backflush'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
cur_frm.cscript.make_se(doc, process = 'Backflush');
|
||||
}
|
||||
|
||||
cur_frm.cscript.make_se = function(doc, process) {
|
||||
var se = LocalDB.create('Stock Entry');
|
||||
se = locals['Stock Entry'][se];
|
||||
se.purpose = 'Production Order';
|
||||
se.process = process;
|
||||
se.posting_date = doc.posting_date;
|
||||
se.production_order = doc.name;
|
||||
se.fiscal_year = doc.fiscal_year;
|
||||
se.company = doc.company;
|
||||
|
||||
loaddoc('Stock Entry', se.name);
|
||||
}
|
||||
|
||||
|
||||
// ==================================================================================================
|
||||
cur_frm.fields_dict['production_item'].get_query = function(doc) {
|
||||
return 'SELECT DISTINCT `tabItem`.`name`, `tabItem`.`description` FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` = "0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.docstatus != 2 AND `tabItem`.is_pro_applicable = "Yes" AND `tabItem`.%(key)s LIKE "%s" ORDER BY `tabItem`.`name` LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
||||
return 'SELECT `tabProject`.name FROM `tabProject` WHERE `tabProject`.status = "Open" AND `tabProject`.name LIKE "%s" ORDER BY `tabProject`.name ASC LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['bom_no'].get_query = function(doc) {
|
||||
if (doc.production_item){
|
||||
return 'SELECT DISTINCT `tabBOM`.`name` FROM `tabBOM` WHERE `tabBOM`.`is_active` = "Yes" AND `tabBOM`.docstatus = 1 AND `tabBOM`.`item` = "' + cstr(doc.production_item) + '" AND`tabBOM`.%(key)s LIKE "%s" ORDER BY `tabBOM`.`name` LIMIT 50';
|
||||
}
|
||||
else {
|
||||
alert(" Please Enter Production Item First.")
|
||||
}
|
||||
}
|
||||
|
||||
114
production/doctype/production_order/production_order.py
Normal file
114
production/doctype/production_order/production_order.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
|
||||
def autoname(self):
|
||||
p = self.doc.fiscal_year
|
||||
self.doc.name = make_autoname('PRO/' + self.doc.fiscal_year[2:5]+self.doc.fiscal_year[7:9] + '/.######')
|
||||
|
||||
|
||||
def get_item_detail(self, prod_item):
|
||||
item = sql("""select description, stock_uom, default_bom from `tabItem`
|
||||
where (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now()) and name = %s""", prod_item, as_dict = 1 )
|
||||
ret = {
|
||||
'description' : item and item[0]['description'] or '',
|
||||
'stock_uom' : item and item[0]['stock_uom'] or '',
|
||||
'default_bom' : item and item[0]['default_bom'] or ''
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
def validate(self):
|
||||
if self.doc.production_item :
|
||||
item_detail = sql("select name from `tabItem` where name = '%s' and docstatus != 2" % self.doc.production_item, as_dict = 1)
|
||||
if not item_detail:
|
||||
msgprint("Item '%s' does not exist or cancelled in the system." % cstr(self.doc.production_item))
|
||||
raise Exception
|
||||
|
||||
if self.doc.bom_no:
|
||||
bom = sql("""select name from `tabBOM` where name = %s and docstatus = 1
|
||||
and is_active = 'Yes' and item = %s""", (self.doc.bom_no, self.doc.production_item), as_dict =1)
|
||||
if not bom:
|
||||
msgprint("""Incorrect BOM: %s entered.
|
||||
May be BOM not exists or inactive or not submitted or for some other item.""" % cstr(self.doc.bom_no))
|
||||
raise Exception
|
||||
|
||||
|
||||
def stop_unstop(self, status):
|
||||
""" Called from client side on Stop/Unstop event"""
|
||||
self.update_status(status)
|
||||
# Update Planned Qty of Production Item
|
||||
qty = (flt(self.doc.qty) - flt(self.doc.produced_qty)) * ((status == 'Stopped') and -1 or 1)
|
||||
get_obj('Warehouse', self.doc.fg_warehouse).update_bin(0, 0, 0, 0, flt(qty), self.doc.production_item, now())
|
||||
msgprint("Production Order has been %s" % status)
|
||||
|
||||
|
||||
|
||||
def update_status(self, status):
|
||||
if status == 'Stopped':
|
||||
set(self.doc, 'status', cstr(status))
|
||||
else:
|
||||
if flt(self.doc.qty) == flt(self.doc.produced_qty):
|
||||
set(self.doc, 'status', 'Completed')
|
||||
if flt(self.doc.qty) > flt(self.doc.produced_qty):
|
||||
set(self.doc, 'status', 'In Process')
|
||||
if flt(self.doc.produced_qty) == 0:
|
||||
set(self.doc, 'status', 'Submitted')
|
||||
|
||||
|
||||
def on_submit(self):
|
||||
set(self.doc,'status', 'Submitted')
|
||||
# increase Planned Qty of Prooduction Item by Qty
|
||||
get_obj('Warehouse', self.doc.fg_warehouse).update_bin(0, 0, 0, 0,flt(self.doc.qty), self.doc.production_item, now())
|
||||
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
# Check whether any stock entry exists against this Production Order
|
||||
st = sql("select name from `tabStock Entry` where production_order = '%s' and docstatus = 1" % cstr(self.doc.name))
|
||||
if st and st[0][0]:
|
||||
msgprint("""Submitted Stock Entry %s exists against this production order.
|
||||
Hence can not be cancelled.""" % st[0][0])
|
||||
raise Exception
|
||||
|
||||
set(self.doc,'status', 'Cancelled')
|
||||
# decrease Planned Qty of Prooduction Item by Qty
|
||||
get_obj('Warehouse', self.doc.fg_warehouse).update_bin(0, 0, 0, 0,-flt(self.doc.qty), self.doc.production_item, now())
|
||||
358
production/doctype/production_order/production_order.txt
Normal file
358
production/doctype/production_order/production_order.txt
Normal file
@@ -0,0 +1,358 @@
|
||||
# DocType, Production Order
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-05-15 12:14:48',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-05-28 19:03:56',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1325837006',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 0,
|
||||
'is_submittable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Tabbed',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Order',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Order',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, Production Order
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Production Order'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'System Manager',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'All'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production Manager',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production User',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Item for which this Production Order is raised.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'production_item',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'Production Item',
|
||||
'oldfieldname': u'production_item',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item',
|
||||
'permlevel': 1,
|
||||
'reqd': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 0,
|
||||
'width': u'300px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'stock_uom',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Stock UOM',
|
||||
'oldfieldname': u'stock_uom',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Bill of Material which was considered for manufacturing the production item.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'bom_no',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'BOM No',
|
||||
'oldfieldname': u'bom_no',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'BOM',
|
||||
'permlevel': 1,
|
||||
'reqd': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Quantity of item for which Production Order is raised.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'qty',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Qty',
|
||||
'oldfieldname': u'qty',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'The warehouse for finished goods where stock of produced items will be updated.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fg_warehouse',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'FG Warehouse',
|
||||
'oldfieldname': u'fg_warehouse',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Warehouse',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'The work in progress warehouse where raw materials will be operated upon to create finished goods.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'wip_warehouse',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'WIP Warehouse',
|
||||
'oldfieldname': u'wip_warehouse',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Warehouse',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amended_from',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Amended From',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'amended_from',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amendment_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Amendment Date',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'amendment_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break1',
|
||||
'fieldtype': u'Column Break',
|
||||
'oldfieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'The date on which current entry will get or has actually executed.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'posting_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Posting Date',
|
||||
'oldfieldname': u'posting_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Select "Yes" if stock is maintained and tracked for sub-assembly items. Select "No" if you want child items of sub-assembly for material transfer.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'consider_sa_items',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Consider SA Items as raw material',
|
||||
'oldfieldname': u'consider_sa_items',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'\nYes\nNo',
|
||||
'permlevel': 1,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'Select name of the project if Production Order need to be created against any project',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'project_name',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'Project Name',
|
||||
'oldfieldname': u'project_name',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Project',
|
||||
'permlevel': 0,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'origin',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Origin',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'origin',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'Manual\nMRP',
|
||||
'permlevel': 1,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'status',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Status',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'status',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled',
|
||||
'permlevel': 1,
|
||||
'reqd': 1,
|
||||
'search_index': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Updated after finished goods are transferred to FG Warehouse through Stock Entry',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'produced_qty',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Produced Qty',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'produced_qty',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'company',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Company',
|
||||
'oldfieldname': u'company',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Company',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fiscal_year',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Fiscal Year',
|
||||
'oldfieldname': u'fiscal_year',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'link:Fiscal Year',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
}
|
||||
]
|
||||
40
production/doctype/production_order/production_order_list.js
Normal file
40
production/doctype/production_order/production_order_list.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// render
|
||||
wn.doclistviews['Production Order'] = wn.views.ListView.extend({
|
||||
init: function(d) {
|
||||
this._super(d);
|
||||
this.fields = this.fields.concat([
|
||||
'`tabProduction Order`.production_item',
|
||||
'`tabProduction Order`.fg_warehouse',
|
||||
'`tabProduction Order`.stock_uom',
|
||||
'IFNULL(`tabProduction Order`.qty, 0) as qty',
|
||||
'`tabProduction Order`.posting_date',
|
||||
'`tabProduction Order`.status',
|
||||
]);
|
||||
this.stats = this.stats.concat(['company']);
|
||||
},
|
||||
|
||||
prepare_data: function(data) {
|
||||
this._super(data);
|
||||
data.posting_date = wn.datetime.str_to_user(data.posting_date);
|
||||
},
|
||||
|
||||
columns: [
|
||||
{width: '3%', content: 'check'},
|
||||
{width: '5%', content: 'avatar'},
|
||||
{width: '3%', content: 'docstatus'},
|
||||
{width: '17%', content: 'name'},
|
||||
{width: '16%', content: 'production_item'},
|
||||
{width: '20%', content: 'fg_warehouse'},
|
||||
{width: '12%', content: 'status+tags'},
|
||||
{
|
||||
width: '12%',
|
||||
content: function(parent, data) {
|
||||
$(parent).html(data.qty + ' ' + data.stock_uom)
|
||||
},
|
||||
css: {'text-align':'right'}
|
||||
},
|
||||
{width: '12%', content:'posting_date', css: {
|
||||
'text-align': 'right', 'color':'#777'
|
||||
}},
|
||||
]
|
||||
});
|
||||
1
production/doctype/production_plan_item/__init__.py
Normal file
1
production/doctype/production_plan_item/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
159
production/doctype/production_plan_item/production_plan_item.txt
Normal file
159
production/doctype/production_plan_item/production_plan_item.txt
Normal file
@@ -0,0 +1,159 @@
|
||||
# DocType, Production Plan Item
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:03',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:03',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'autoname': u'PPID/.#####',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 27
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Plan Item',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# DocType, Production Plan Item
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Production Plan Item'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sales_order',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Sales Order',
|
||||
'oldfieldname': u'source_docname',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'item_code',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Item Code',
|
||||
'oldfieldname': u'item_code',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'trigger': u'Client',
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'bom_no',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'BOM No',
|
||||
'oldfieldname': u'bom_no',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'BOM',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'width': u'100px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'default': u'0.00',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'so_pending_qty',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'SO Pending Qty',
|
||||
'oldfieldname': u'prevdoc_reqd_qty',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1,
|
||||
'reqd': 0,
|
||||
'width': u'100px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'default': u'0.00',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'planned_qty',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Planned Qty',
|
||||
'oldfieldname': u'planned_qty',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'width': u'100px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'stock_uom',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'UOM',
|
||||
'oldfieldname': u'stock_uom',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1,
|
||||
'reqd': 1,
|
||||
'width': u'80px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 1,
|
||||
'width': u'200px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'parent_packing_item',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Parent Packing Item',
|
||||
'oldfieldname': u'parent_item',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Item',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_pro_created',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Is PRO Created',
|
||||
'oldfieldname': u'pro_created',
|
||||
'oldfieldtype': u'Check',
|
||||
'permlevel': 1
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1,124 @@
|
||||
# DocType, Production Plan Sales Order
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:04',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:04',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'autoname': u'PP/.SO/.#####',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 5
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Plan Sales Order',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Plan Sales Order',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocType, Production Plan Sales Order
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Production Plan Sales Order'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sales_order',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Sales Order',
|
||||
'oldfieldname': u'prevdoc_docname',
|
||||
'oldfieldtype': u'Data',
|
||||
'options': u'Sales Order',
|
||||
'permlevel': 0,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sales_order_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Sales Order Date',
|
||||
'oldfieldname': u'document_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'permlevel': 1,
|
||||
'width': u'100px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Customer',
|
||||
'options': u'Customer',
|
||||
'permlevel': 1,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'grand_total',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Grand Total',
|
||||
'permlevel': 1,
|
||||
'width': u'100px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'include_in_plan',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Include In Plan',
|
||||
'oldfieldname': u'include_in_plan',
|
||||
'oldfieldtype': u'Check',
|
||||
'permlevel': 0,
|
||||
'width': u'100px'
|
||||
}
|
||||
]
|
||||
1
production/doctype/production_planning_tool/__init__.py
Normal file
1
production/doctype/production_planning_tool/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1,50 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
cur_frm.cscript.item_code = function(doc,cdt,cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.item_code) {
|
||||
get_server_fields('get_item_details', d.item_code, 'pp_details', doc, cdt, cdn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.sales_order = function(doc,cdt,cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.sales_order) {
|
||||
get_server_fields('get_so_details', d.sales_order, 'pp_so_details', doc, cdt, cdn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.download_raw_material = function(doc, cdt, cdn) {
|
||||
var callback = function(r, rt){
|
||||
if (r.message)
|
||||
$c_obj_csv(make_doclist(cdt, cdn), 'download_raw_materials', '', '');
|
||||
}
|
||||
$c_obj(make_doclist(cdt, cdn), 'validate_data', '', callback)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
cur_frm.fields_dict['pp_details'].grid.get_field('item_code').get_query = function(doc) {
|
||||
return 'SELECT DISTINCT `tabItem`.`name`,`tabItem`.`item_name` FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life`="0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.is_pro_applicable = "Yes" AND tabItem.%(key)s like "%s" ORDER BY `tabItem`.`name` LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['pp_details'].grid.get_field('bom_no').get_query = function(doc) {
|
||||
var d = locals[this.doctype][this.docname];
|
||||
return 'SELECT DISTINCT `tabBOM`.`name` FROM `tabBOM` WHERE `tabBOM`.`item` = "' + d.item_code + '" AND `tabBOM`.`is_active` = "Yes" AND `tabBOM`.docstatus = 1 AND `tabBOM`.`name` like "%s" ORDER BY `tabBOM`.`name` LIMIT 50';
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint, cstr, flt, getdate, now, nowdate
|
||||
from webnotes.model.doc import addchild
|
||||
from webnotes.model.doclist import getlist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint, errprint
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
self.item_dict = {}
|
||||
|
||||
def get_item_details(self, item_code):
|
||||
""" Pull other item details from item master"""
|
||||
|
||||
item = sql("""select description, stock_uom, default_bom from `tabItem` where name = %s
|
||||
and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now())""", item_code, as_dict =1 )
|
||||
ret = {
|
||||
'description' : item and item[0]['description'],
|
||||
'stock_uom' : item and item[0]['stock_uom'],
|
||||
'bom_no' : item and item[0]['default_bom']
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
def get_so_details(self, so):
|
||||
"""Pull other details from so"""
|
||||
so = sql("select transaction_date, customer, grand_total from `tabSales Order` where name = %s", so, as_dict = 1)
|
||||
ret = {
|
||||
'sales_order_date': so and so[0]['transaction_date'] or '',
|
||||
'customer' : so[0]['customer'] or '',
|
||||
'grand_total': so[0]['grand_total']
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
def clear_so_table(self):
|
||||
""" Clears sales order table"""
|
||||
self.doclist = self.doc.clear_table(self.doclist, 'pp_so_details')
|
||||
|
||||
|
||||
|
||||
def clear_item_table(self):
|
||||
""" Clears item table"""
|
||||
self.doclist = self.doc.clear_table(self.doclist, 'pp_details')
|
||||
|
||||
|
||||
|
||||
def get_open_sales_orders(self):
|
||||
""" Pull sales orders which are pending to deliver based on criteria selected"""
|
||||
cond = self.get_filter_condition()
|
||||
open_so = sql("""
|
||||
select
|
||||
distinct t1.name, t1.transaction_date, t1.customer, t1.grand_total
|
||||
from
|
||||
`tabSales Order` t1, `tabSales Order Item` t2, `tabDelivery Note Packing Item` t3, tabItem t4
|
||||
where
|
||||
t1.name = t2.parent and t1.name = t3.parent and t3.parenttype = 'Sales Order' and t1.docstatus = 1 and t2.item_code = t3.parent_item
|
||||
and t4.name = t3.item_code and t1.status != 'Stopped' and t1.company = '%s' and ifnull(t2.qty, 0) > ifnull(t2.delivered_qty, 0)
|
||||
and (ifnull(t4.is_pro_applicable, 'No') = 'Yes' or ifnull(t4.is_sub_contracted_item, 'No') = 'Yes') %s
|
||||
order by t1.name desc
|
||||
"""% (self.doc.company, cond), as_dict = 1)
|
||||
|
||||
self.add_so_in_table(open_so)
|
||||
|
||||
|
||||
|
||||
def validate_company(self):
|
||||
if not self.doc.company:
|
||||
msgprint("Please enter Company", raise_exception=1)
|
||||
|
||||
|
||||
|
||||
def get_filter_condition(self):
|
||||
self.validate_company()
|
||||
|
||||
cond = ''
|
||||
if self.doc.from_date:
|
||||
cond += ' and t1.transaction_date >= "' + self.doc.from_date + '"'
|
||||
if self.doc.to_date:
|
||||
cond += ' and t1.transaction_date <= "' + self.doc.to_date + '"'
|
||||
if self.doc.customer:
|
||||
cond += ' and t1.customer = "' + self.doc.customer + '"'
|
||||
if self.doc.fg_item:
|
||||
cond += ' and t3.item_code = "' + self.doc.fg_item + '"'
|
||||
|
||||
return cond
|
||||
|
||||
|
||||
|
||||
def add_so_in_table(self, open_so):
|
||||
""" Add sales orders in the table"""
|
||||
so_list = []
|
||||
for d in getlist(self.doclist, 'pp_so_details'):
|
||||
so_list.append(d.sales_order)
|
||||
for r in open_so:
|
||||
if cstr(r['name']) not in so_list:
|
||||
pp_so = addchild(self.doc, 'pp_so_details', 'Production Plan Sales Order', 1, self.doclist)
|
||||
pp_so.sales_order = r['name']
|
||||
pp_so.sales_order_date = cstr(r['transaction_date'])
|
||||
pp_so.customer = cstr(r['customer'])
|
||||
pp_so.grand_total = flt(r['grand_total'])
|
||||
|
||||
|
||||
|
||||
def get_items_from_so(self):
|
||||
""" Pull items from Sales Order, only proction item
|
||||
and subcontracted item will be pulled from Packing item
|
||||
and add items in the table
|
||||
"""
|
||||
so = self.get_included_so()
|
||||
items = self.get_packing_items(so)
|
||||
self.add_items(items)
|
||||
|
||||
|
||||
def get_included_so(self):
|
||||
so = "'" + "','".join([cstr(d.sales_order) for d in getlist(self.doclist, 'pp_so_details') if d.include_in_plan]) + "'"
|
||||
return so
|
||||
|
||||
|
||||
|
||||
def get_packing_items(self, so):
|
||||
packing_items = sql("""
|
||||
select
|
||||
t0.name, t2.parent_item, t2.item_code,
|
||||
(t1.qty - ifnull(t1.delivered_qty,0)) * (ifnull(t2.qty,0) / ifnull(t1.qty,1)) as 'pending_qty'
|
||||
from
|
||||
`tabSales Order` t0, `tabSales Order Item` t1, `tabDelivery Note Packing Item` t2, `tabItem` t3
|
||||
where
|
||||
t0.name = t1.parent and t0.name = t2.parent and t1.name = t2.parent_detail_docname
|
||||
and t0.name in (%s) and t0.docstatus = 1 and t1.qty > ifnull(t1.delivered_qty,0) and t3.name = t2.item_code
|
||||
and (ifnull(t3.is_pro_applicable, 'No') = 'Yes' or ifnull(t3.is_sub_contracted_item, 'No') = 'Yes')
|
||||
""" % so, as_dict=1)
|
||||
return packing_items
|
||||
|
||||
|
||||
|
||||
def add_items(self, packing_items):
|
||||
for d in getlist(self.doclist, 'pp_details'):
|
||||
if d.sales_order:
|
||||
d.parent = ''
|
||||
|
||||
for p in packing_items:
|
||||
item_details = sql("select description, stock_uom, default_bom from tabItem where name=%s", p['item_code'])
|
||||
pi = addchild(self.doc, 'pp_details', 'Production Plan Item', 1, self.doclist)
|
||||
pi.sales_order = p['name']
|
||||
pi.parent_packing_item = p['parent_item']
|
||||
pi.item_code = p['item_code']
|
||||
pi.description = item_details and item_details[0][0] or ''
|
||||
pi.stock_uom = item_details and item_details[0][1] or ''
|
||||
pi.bom_no = item_details and item_details[0][2] or ''
|
||||
pi.so_pending_qty = flt(p['pending_qty'])
|
||||
pi.planned_qty = flt(p['pending_qty'])
|
||||
|
||||
|
||||
|
||||
def validate_data(self):
|
||||
for d in getlist(self.doclist, 'pp_details'):
|
||||
if not d.pro_created:
|
||||
self.validate_bom_no(d)
|
||||
|
||||
if not flt(d.planned_qty):
|
||||
msgprint("Please Enter Planned Qty for item: %s at row no: %s"% (d.item_code, d.idx), raise_exception=1)
|
||||
return 'validated'
|
||||
|
||||
|
||||
|
||||
def validate_bom_no(self, d):
|
||||
if not d.bom_no:
|
||||
msgprint("Please enter bom no for item: %s at row no: %s" % (d.item_code, d.idx), raise_exception=1)
|
||||
else:
|
||||
bom = sql("""select name from `tabBOM` where item = %s and docstatus = 1
|
||||
and name = %s and ifnull(is_active, 'No') = 'Yes'""", (d.item_code, d.bom_no), as_dict = 1)
|
||||
if not bom:
|
||||
msgprint("""Incorrect BOM No: %s entered for item: %s at row no: %s
|
||||
May be BOM is inactive or for other item or does not exists in the system"""% (d.bom_no, d.item_doce, d.idx))
|
||||
|
||||
|
||||
|
||||
def download_raw_materials(self):
|
||||
""" Create csv data for required raw material to produce finished goods"""
|
||||
bom_dict = self.get_distinct_bom(action = 'download_rm')
|
||||
self.get_raw_materials(bom_dict)
|
||||
return self.get_csv()
|
||||
|
||||
|
||||
|
||||
|
||||
def get_raw_materials(self, bom_dict):
|
||||
""" Get raw materials considering sub-assembly items """
|
||||
for bom in bom_dict:
|
||||
if self.doc.consider_sa_items == 'Yes':
|
||||
# Get all raw materials considering SA items as raw materials,
|
||||
# so no childs of SA items
|
||||
fl_bom_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
|
||||
""" % (flt(bom_dict[bom]), bom))
|
||||
|
||||
else:
|
||||
# get all raw materials with sub assembly childs
|
||||
fl_bom_items = 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
|
||||
""" , (flt(bom_dict[bom]), bom))
|
||||
|
||||
self.make_items_dict(fl_bom_items)
|
||||
|
||||
|
||||
|
||||
def make_items_dict(self, item_list):
|
||||
for i in item_list:
|
||||
self.item_dict[i[0]] = [(flt(self.item_dict.get(i[0], [0])[0]) + flt(i[1])), i[2], i[3]]
|
||||
|
||||
|
||||
def get_csv(self):
|
||||
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse', 'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
|
||||
for d in self.item_dict:
|
||||
item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]]),
|
||||
item_qty= sql("select warehouse, indented_qty, ordered_qty, actual_qty from `tabBin` where item_code = %s", d)
|
||||
i_qty, o_qty, a_qty = 0,0,0
|
||||
for w in item_qty:
|
||||
i_qty, o_qty, a_qty = i_qty + flt(w[1]), o_qty + flt(w[2]), a_qty + flt(w[3])
|
||||
item_list.append(['', '', '', '', w[0], flt(w[1]), flt(w[2]), flt(w[3])])
|
||||
if item_qty:
|
||||
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
|
||||
|
||||
return item_list
|
||||
|
||||
|
||||
|
||||
def raise_production_order(self):
|
||||
"""It will raise production order (Draft) for all distinct FG items"""
|
||||
self.validate_company()
|
||||
self.validate_data()
|
||||
|
||||
pp_items = self.get_distinct_bom(action = 'raise_pro_order')
|
||||
pro = get_obj(dt = 'Production Control').create_production_order(self.doc.company, pp_items)
|
||||
if pro:
|
||||
for d in getlist(self.doclist, 'pp_details'):
|
||||
d.is_pro_created = 1
|
||||
msgprint("Following Production Order has been generated:\n" + '\n'.join(pro))
|
||||
else :
|
||||
msgprint("No Production Order is generated.")
|
||||
|
||||
|
||||
|
||||
def get_distinct_bom(self, action):
|
||||
""" Club similar BOM and item for processing"""
|
||||
|
||||
bom_dict, item_dict, pp_items = {}, {}, []
|
||||
for d in getlist(self.doclist, 'pp_details'):
|
||||
if action == 'download_rm':
|
||||
bom_dict[d.bom_no] = bom_dict.get(d.bom_no, 0) + flt(d.planned_qty)
|
||||
elif not d.is_pro_created:
|
||||
item_dict[d.item_code] = [(item_dict.get(d.item_code, 0) + flt(d.planned_qty)), d.bom_no, d.description, d.stock_uom]
|
||||
|
||||
if action == 'raise_pro_order':
|
||||
for d in item_dict:
|
||||
pp_items.append({
|
||||
'production_item' : d,
|
||||
'qty' : item_dict[d][0],
|
||||
'bom_no' : item_dict[d][1],
|
||||
'description' : item_dict[d][2],
|
||||
'stock_uom' : item_dict[d][3],
|
||||
'consider_sa_items' : self.doc.consider_sa_items
|
||||
})
|
||||
|
||||
return action == 'download_rm' and bom_dict or pp_items
|
||||
@@ -0,0 +1,318 @@
|
||||
# DocType, Production Planning Tool
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:05',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:05',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'jai@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1326188323',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 1,
|
||||
'issingle': 1,
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'section_style': u'Tabbed',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 1,
|
||||
'version': 106
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Planning Tool',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Production Planning Tool',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocType, Production Planning Tool
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Production Planning Tool'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'Production User'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'Production Manager'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'select_sales_orders',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Select Sales Orders'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'from_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'From Date'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'to_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'To Date'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fg_item',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'FG Item',
|
||||
'options': u'Item'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break1',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Customer',
|
||||
'options': u'Customer'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'company',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Company',
|
||||
'options': u'Company',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'section_break0',
|
||||
'fieldtype': u'Section Break',
|
||||
'options': u'Simple'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break2',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'get_sales_orders',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Get Sales Orders',
|
||||
'options': u'get_open_sales_orders'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break3',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'clear_so_table',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Clear SO Table',
|
||||
'options': u'clear_so_table',
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'section_break1',
|
||||
'fieldtype': u'Section Break',
|
||||
'options': u'Simple'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'Select Sales Orders from which you want to create Production Orders. You can get sales orders based on above criteria.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'pp_so_details',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'Production Plan Sales Orders',
|
||||
'options': u'Production Plan Sales Order'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'items',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Items'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'get_items_from_so',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Get Items from SO',
|
||||
'options': u'get_items_from_so'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break4',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'clear_item_table',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Clear Item Table',
|
||||
'options': u'clear_item_table',
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'section_break2',
|
||||
'fieldtype': u'Section Break',
|
||||
'options': u'Simple'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'Enter items and planned qty for which you want to raise production orders or download raw materials for analysis. You can pull items (which are pending to deliver) from SO as well by adding SO in plan.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'pp_details',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'Production Plan Items',
|
||||
'options': u'Production Plan Item'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'No',
|
||||
'description': u'Select "Yes" if stock is maintained and tracked for sub assembly items.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'consider_sa_items',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'Consider Sub Assemblies as Raw Material',
|
||||
'options': u'No\nYes',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'section_break3',
|
||||
'fieldtype': u'Section Break',
|
||||
'options': u'Simple'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break5',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'raise_production_order',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Raise Production Order',
|
||||
'options': u'raise_production_order'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break6',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'download_raw_material',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Download Raw Material',
|
||||
'trigger': u'Client'
|
||||
}
|
||||
]
|
||||
1
production/doctype/workstation/__init__.py
Normal file
1
production/doctype/workstation/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
26
production/doctype/workstation/workstation.js
Normal file
26
production/doctype/workstation/workstation.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
//--------- ONLOAD -------------
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
|
||||
}
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||
|
||||
}
|
||||
50
production/doctype/workstation/workstation.py
Normal file
50
production/doctype/workstation/workstation.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def update_bom_operation(self):
|
||||
bom_list = sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name)
|
||||
for bom_no in bom_list:
|
||||
sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name))
|
||||
|
||||
def on_update(self):
|
||||
set(self.doc, 'overhead', flt(self.doc.hour_rate_electricity) + flt(self.doc.hour_rate_consumable) + flt(self.doc.hour_rate_rent))
|
||||
set(self.doc, 'hour_rate', flt(self.doc.hour_rate_labour) + flt(self.doc.overhead))
|
||||
self.update_bom_operation()
|
||||
269
production/doctype/workstation/workstation.txt
Normal file
269
production/doctype/workstation/workstation.txt
Normal file
@@ -0,0 +1,269 @@
|
||||
# DocType, Workstation
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:05',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 18:46:49',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1322125389',
|
||||
'allow_email': 0,
|
||||
'allow_trash': 1,
|
||||
'autoname': u'field:workstation_name',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'document_type': u'Master',
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 14
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Workstation',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Workstation',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, Workstation
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Workstation'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'System Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Production User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'Production Manager'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'Production User'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'trash_reason',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Trash Reason',
|
||||
'oldfieldname': u'trash_reason',
|
||||
'oldfieldtype': u'Small Text',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'workstation_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Workstation Name',
|
||||
'oldfieldname': u'workstation_name',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'warehouse',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Warehouse',
|
||||
'oldfieldname': u'warehouse',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Warehouse',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Text',
|
||||
'permlevel': 0,
|
||||
'width': u'300px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'capacity',
|
||||
'fieldtype': u'Data',
|
||||
'hidden': 1,
|
||||
'label': u'Capacity',
|
||||
'oldfieldname': u'capacity',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'capacity_units',
|
||||
'fieldtype': u'Select',
|
||||
'hidden': 1,
|
||||
'label': u'Capacity Units',
|
||||
'oldfieldname': u'capacity_units',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'\nUnits/Shifts\nUnits/Hour',
|
||||
'permlevel': 0,
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate_labour',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate Labour',
|
||||
'oldfieldname': u'hour_rate_labour',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0,
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'over_heads',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Over Heads',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate_electricity',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate Electricity',
|
||||
'oldfieldname': u'hour_rate_electricity',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate_consumable',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate Consumable',
|
||||
'oldfieldname': u'hour_rate_consumable',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate_rent',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate Rent',
|
||||
'oldfieldname': u'hour_rate_rent',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'overhead',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Overhead',
|
||||
'oldfieldname': u'overhead',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate_section_break',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Hour Rate',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'hour_rate',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Hour Rate',
|
||||
'oldfieldname': u'hour_rate',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1
|
||||
}
|
||||
]
|
||||
1
production/page/__init__.py
Normal file
1
production/page/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
1
production/page/production_home/__init__.py
Normal file
1
production/page/production_home/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
38
production/page/production_home/production_home.html
Normal file
38
production/page/production_home/production_home.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<div class="layout-wrapper layout-wrapper-background">
|
||||
<div class="appframe-area"></div>
|
||||
<div class="layout-main-section">
|
||||
<div style="width: 48%; float: left;">
|
||||
<h4><a href="#!List/Production Order">Production Order</a></h4>
|
||||
<p class="help">Orders for manufacturing</p>
|
||||
<br>
|
||||
<h4><a href="#!Form/Production Planning Tool/Production Planning Tool">Production Plan</a></h4>
|
||||
<p class="help">Generate Purchase Requisition (MRP) and Production Orders</p>
|
||||
</div>
|
||||
<div style="width: 48%; float: right;">
|
||||
<h4><a href="#!List/BOM">Bill of Materials</a></h4>
|
||||
<p class="help">Bill of Materials (BOM) Master</p>
|
||||
<br>
|
||||
<h4><a href="#!List/Item">Item</a></h4>
|
||||
<p class="help">Item Master</p>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
<hr>
|
||||
<h3>Reports</h3>
|
||||
<div class="reports-list"></div>
|
||||
</div>
|
||||
<div class="layout-side-section">
|
||||
<div class="psidebar">
|
||||
<div class="section">
|
||||
<div class="section-head">Setup</div>
|
||||
<div class="section-body">
|
||||
<div class="section-item">
|
||||
<a class="section-link"
|
||||
title = "Workstation master"
|
||||
href="#!List/Workstation">Workstations</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
20
production/page/production_home/production_home.js
Normal file
20
production/page/production_home/production_home.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
pscript['onload_production-home'] = function(wrapper) {
|
||||
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.appframe-area'), 'Production');
|
||||
erpnext.module_page.setup_page('Production', wrapper);
|
||||
}
|
||||
28
production/page/production_home/production_home.txt
Normal file
28
production/page/production_home/production_home.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, production-home
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-02-21 13:24:34',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-02-21 13:24:34',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'page_name': u'production-home',
|
||||
'standard': u'Yes',
|
||||
'title': u'Production Home'
|
||||
},
|
||||
|
||||
# Page, production-home
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'production-home'
|
||||
}
|
||||
]
|
||||
1
production/search_criteria/__init__.py
Normal file
1
production/search_criteria/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1,37 @@
|
||||
# Search Criteria, consumption_against_production
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-03 12:49:50',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-03 12:49:50',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'jai@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all Search Criteria
|
||||
{
|
||||
'add_col': u'`tabProduction Order`.consider_sa_items',
|
||||
'add_cond': u'`tabProduction Order`.name = `tabStock Entry`.production_order',
|
||||
'add_tab': u'`tabProduction Order`',
|
||||
'columns': u'Stock Entry\x01ID,Stock Entry\x01Production Order,Stock Entry\x01Process,Stock Entry\x01Posting Date,Stock Entry\x01Company,Stock Entry Detail\x01Source Warehouse,Stock Entry Detail\x01Target Warehouse,Stock Entry Detail\x01FG Item,Stock Entry Detail\x01Item Code,Stock Entry Detail\x01Description,Stock Entry Detail\x01Reqd Qty,Stock Entry Detail\x01Transfer Quantity',
|
||||
'criteria_name': u'Consumption Against Production',
|
||||
'doc_type': u'Stock Entry Detail',
|
||||
'doctype': 'Search Criteria',
|
||||
'filters': u"{'Stock Entry\x01Submitted':1,'Stock Entry\x01Purpose':'Production Order','Stock Entry\x01Process':''}",
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'page_len': 50,
|
||||
'parent_doc_type': u'Stock Entry',
|
||||
'sort_by': u'`tabStock Entry`.`name`',
|
||||
'sort_order': u'DESC',
|
||||
'standard': u'Yes'
|
||||
},
|
||||
|
||||
# Search Criteria, consumption_against_production
|
||||
{
|
||||
'doctype': 'Search Criteria',
|
||||
'name': u'consumption_against_production'
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1,32 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
report.customize_filters = function() {
|
||||
|
||||
//to hide all filters
|
||||
this.hide_all_filters();
|
||||
|
||||
// to unhide required filters
|
||||
this.filter_fields_dict['Stock Entry'+FILTER_SEP +'ID'].df.filter_hide = 0;
|
||||
this.filter_fields_dict['Stock Entry'+FILTER_SEP +'Production Order'].df.filter_hide = 0;
|
||||
|
||||
this.filter_fields_dict['Stock Entry'+FILTER_SEP +'From Posting Date'].df.filter_hide = 0;
|
||||
this.filter_fields_dict['Stock Entry'+FILTER_SEP +'To Posting Date'].df.filter_hide = 0;
|
||||
|
||||
this.filter_fields_dict['Stock Entry Detail'+FILTER_SEP +'Target Warehouse'].df.filter_hide = 0;
|
||||
|
||||
this.filter_fields_dict['Stock Entry Detail'+FILTER_SEP +'Item Code'].df.filter_hide = 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Search Criteria, itemwise_production_report
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-03 12:49:51',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-03 12:49:51',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'jai@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all Search Criteria
|
||||
{
|
||||
'columns': u'Stock Entry\x01ID,Stock Entry\x01Posting Date,Stock Entry\x01Production Order,Stock Entry\x01Process,Stock Entry\x01Company,Stock Entry Detail\x01Target Warehouse,Stock Entry Detail\x01Item Code,Stock Entry Detail\x01Description,Stock Entry Detail\x01Stock UOM,Stock Entry Detail\x01Transfer Quantity',
|
||||
'criteria_name': u'Itemwise Production Report',
|
||||
'doc_type': u'Stock Entry Detail',
|
||||
'doctype': 'Search Criteria',
|
||||
'filters': u"{'Stock Entry\x01Saved':1,'Stock Entry\x01Submitted':1,'Stock Entry\x01Purpose':'Production Order','Stock Entry\x01Process':'Backflush','Stock Entry Detail\x01FG Item':1}",
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'page_len': 50,
|
||||
'parent_doc_type': u'Stock Entry',
|
||||
'sort_by': u'`tabStock Entry`.`name`',
|
||||
'sort_order': u'DESC',
|
||||
'standard': u'Yes'
|
||||
},
|
||||
|
||||
# Search Criteria, itemwise_production_report
|
||||
{
|
||||
'doctype': 'Search Criteria',
|
||||
'name': u'itemwise_production_report'
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -0,0 +1,34 @@
|
||||
# Search Criteria, production_orders_in_process
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-03 12:49:52',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-03 12:49:52',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'jai@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all Search Criteria
|
||||
{
|
||||
'add_cond': u'`tabProduction Order`.qty > `tabProduction Order`.produced_qty',
|
||||
'columns': u'Production Order\x01ID,Production Order\x01Origin,Production Order\x01Status,Production Order\x01Posting Date,Production Order\x01Production Item,Production Order\x01BOM No,Production Order\x01Description,Production Order\x01Stock UOM,Production Order\x01Qty,Production Order\x01Produced Qty,Production Order\x01FG Warehouse,Production Order\x01WIP Warehouse,Production Order\x01Consider SA Items,Production Order\x01Fiscal Year,Production Order\x01Company',
|
||||
'criteria_name': u'Production Orders In Process',
|
||||
'doc_type': u'Production Order',
|
||||
'doctype': 'Search Criteria',
|
||||
'filters': u"{'Production Order\x01Submitted':1,'Production Order\x01Origin':'','Production Order\x01Status':'','Production Order\x01Consider SA Items':'','Production Order\x01Fiscal Year':''}",
|
||||
'module': u'Production',
|
||||
'name': '__common__',
|
||||
'page_len': 50,
|
||||
'sort_by': u'`tabProduction Order`.`name`',
|
||||
'sort_order': u'DESC',
|
||||
'standard': u'Yes'
|
||||
},
|
||||
|
||||
# Search Criteria, production_orders_in_process
|
||||
{
|
||||
'doctype': 'Search Criteria',
|
||||
'name': u'production_orders_in_process'
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user