[removed merge conflict]
This commit is contained in:
commit
5ee811d842
@ -252,6 +252,11 @@ wn.module_page["Accounts"] = [
|
|||||||
route: "query-report/Item-wise Sales Register",
|
route: "query-report/Item-wise Sales Register",
|
||||||
doctype: "Sales Invoice"
|
doctype: "Sales Invoice"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label":wn._("Item-wise Purchase Register"),
|
||||||
|
route: "query-report/Item-wise Purchase Register",
|
||||||
|
doctype: "Purchase Invoice"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
wn.query_reports["Item-wise Purchase Register"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"from_date",
|
||||||
|
"label": "From Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": wn.defaults.get_user_default("year_start_date"),
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"to_date",
|
||||||
|
"label": "To Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": get_today()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "item_code",
|
||||||
|
"label": "Item",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"account",
|
||||||
|
"label": "Account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"get_query": function() {
|
||||||
|
return {
|
||||||
|
"query": "accounts.utils.get_account_list",
|
||||||
|
"filters": {
|
||||||
|
"is_pl_account": "No",
|
||||||
|
"debit_or_credit": "Credit",
|
||||||
|
"master_type": "Supplier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
columns = get_columns()
|
||||||
|
item_list = get_items(filters)
|
||||||
|
aii_account_map = get_aii_accounts()
|
||||||
|
webnotes.errprint(aii_account_map)
|
||||||
|
data = []
|
||||||
|
for d in item_list:
|
||||||
|
expense_head = d.expense_head or aii_account_map.get(d.company)
|
||||||
|
data.append([d.item_code, d.item_name, d.item_group, d.name, d.posting_date, d.supplier,
|
||||||
|
d.credit_to, d.project_name, d.company, d.purchase_order, d.purchase_receipt,
|
||||||
|
expense_head, d.qty, d.rate, d.amount])
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return ["Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
|
||||||
|
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Customer:120",
|
||||||
|
"Supplier Account:Link/Account:120", "Project:Link/Project:80", "Company:Link/Company:100",
|
||||||
|
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100",
|
||||||
|
"Expense Account:Link/Account:140", "Qty:Float:120", "Rate:Currency:120",
|
||||||
|
"Amount:Currency:120"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_conditions(filters):
|
||||||
|
conditions = ""
|
||||||
|
|
||||||
|
if filters.get("account"): conditions += " and pi.credit_to = %(account)s"
|
||||||
|
|
||||||
|
if filters.get("item_code"): conditions += " and pi_item.item_code = %(item_code)s"
|
||||||
|
|
||||||
|
if filters.get("from_date"): conditions += " and pi.posting_date>=%(from_date)s"
|
||||||
|
if filters.get("to_date"): conditions += " and pi.posting_date<=%(to_date)s"
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
def get_items(filters):
|
||||||
|
conditions = get_conditions(filters)
|
||||||
|
return webnotes.conn.sql("""select pi.name, pi.posting_date, pi.credit_to, pi.company,
|
||||||
|
pi.supplier, pi.remarks, pi_item.item_code, pi_item.item_name, pi_item.item_group,
|
||||||
|
pi_item.project_name, pi_item.purchase_order, pi_item.purchase_receipt,
|
||||||
|
pi_item.expense_head, pi_item.qty, pi_item.rate, pi_item.amount
|
||||||
|
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
|
||||||
|
where pi.name = pi_item.parent and pi.docstatus = 1 %s
|
||||||
|
order by pi.posting_date desc, pi_item.item_code desc""" % conditions, filters, as_dict=1)
|
||||||
|
|
||||||
|
def get_aii_accounts():
|
||||||
|
aii_account_map = {}
|
||||||
|
for d in webnotes.conn.sql("select name, stock_received_but_not_billed from tabCompany",
|
||||||
|
as_dict=1):
|
||||||
|
aii_account_map.setdefault(d.name, d.stock_received_but_not_billed)
|
||||||
|
|
||||||
|
return aii_account_map
|
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"creation": "2013-06-05 15:37:30",
|
||||||
|
"docstatus": 0,
|
||||||
|
"modified": "2013-06-05 15:37:30",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"owner": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"add_total_row": 1,
|
||||||
|
"doctype": "Report",
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"name": "__common__",
|
||||||
|
"ref_doctype": "Purchase Invoice",
|
||||||
|
"report_name": "Item-wise Purchase Register",
|
||||||
|
"report_type": "Script Report"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"name": "Item-wise Purchase Register"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,39 @@
|
|||||||
|
wn.query_reports["Item-wise Sales Register"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"from_date",
|
||||||
|
"label": "From Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": wn.defaults.get_user_default("year_start_date"),
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"to_date",
|
||||||
|
"label": "To Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": get_today()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "item_code",
|
||||||
|
"label": "Item",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"account",
|
||||||
|
"label": "Account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"get_query": function() {
|
||||||
|
return {
|
||||||
|
"query": "accounts.utils.get_account_list",
|
||||||
|
"filters": {
|
||||||
|
"is_pl_account": "No",
|
||||||
|
"debit_or_credit": "Debit",
|
||||||
|
"master_type": "Customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
# 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 flt
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
columns = get_columns()
|
||||||
|
item_list = get_items(filters)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for d in item_list:
|
||||||
|
data.append([d.item_code, d.item_name, d.item_group, d.name, d.posting_date, d.customer,
|
||||||
|
d.debit_to, d.territory, d.project_name, d.company, d.sales_order, d.delivery_note,
|
||||||
|
d.income_account, d.qty, d.basic_rate, d.amount])
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [
|
||||||
|
"Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
|
||||||
|
"Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer:Link/Customer:120",
|
||||||
|
"Customer Account:Link/Account:120", "Territory:Link/Territory:80",
|
||||||
|
"Project:Link/Project:80", "Company:Link/Company:100", "Sales Order:Link/Sales Order:100",
|
||||||
|
"Delivery Note:Link/Delivery Note:100", "Income Account:Link/Account:140",
|
||||||
|
"Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_conditions(filters):
|
||||||
|
conditions = ""
|
||||||
|
|
||||||
|
if filters.get("account"): conditions += " and si.debit_to = %(account)s"
|
||||||
|
|
||||||
|
if filters.get("item_code"): conditions += " and si_item.item_code = %(item_code)s"
|
||||||
|
|
||||||
|
if filters.get("from_date"): conditions += " and si.posting_date>=%(from_date)s"
|
||||||
|
if filters.get("to_date"): conditions += " and si.posting_date<=%(to_date)s"
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
def get_items(filters):
|
||||||
|
conditions = get_conditions(filters)
|
||||||
|
return webnotes.conn.sql("""select si.name, si.posting_date, si.debit_to, si.project_name,
|
||||||
|
si.customer, si.remarks, si.territory, si_item.item_code, si_item.item_name,
|
||||||
|
si_item.item_group, si_item.sales_order, si_item.delivery_note, si_item.income_account,
|
||||||
|
si_item.qty, si_item.basic_rate, si_item.amount
|
||||||
|
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
|
||||||
|
where si.name = si_item.parent and si.docstatus = 1 %s
|
||||||
|
order by si.posting_date desc, si_item.item_code desc""" % conditions, filters, as_dict=1)
|
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"creation": "2013-05-13 17:50:55",
|
||||||
|
"docstatus": 0,
|
||||||
|
"modified": "2013-05-13 17:50:55",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"owner": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"add_total_row": 1,
|
||||||
|
"doctype": "Report",
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"name": "__common__",
|
||||||
|
"ref_doctype": "Sales Invoice",
|
||||||
|
"report_name": "Item-wise Sales Register",
|
||||||
|
"report_type": "Script Report"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"name": "Item-wise Sales Register"
|
||||||
|
}
|
||||||
|
]
|
@ -266,22 +266,27 @@ class DocType:
|
|||||||
for b in boms:
|
for b in boms:
|
||||||
if b[0] == self.doc.name:
|
if b[0] == self.doc.name:
|
||||||
msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'.
|
msgprint("""Recursion Occured => '%s' cannot be '%s' of '%s'.
|
||||||
""" % (cstr(b), cstr(d[2]), self.doc.name), raise_exception = 1)
|
""" % (cstr(b[0]), cstr(d[2]), self.doc.name), raise_exception = 1)
|
||||||
if b[0]:
|
if b[0]:
|
||||||
bom_list.append(b[0])
|
bom_list.append(b[0])
|
||||||
|
|
||||||
def update_cost_and_exploded_items(self):
|
def update_cost_and_exploded_items(self, bom_list=[]):
|
||||||
bom_list = self.traverse_tree()
|
bom_list = self.traverse_tree(bom_list)
|
||||||
for bom in bom_list:
|
for bom in bom_list:
|
||||||
bom_obj = get_obj("BOM", bom, with_children=1)
|
bom_obj = get_obj("BOM", bom, with_children=1)
|
||||||
bom_obj.on_update()
|
bom_obj.on_update()
|
||||||
|
|
||||||
def traverse_tree(self):
|
return bom_list
|
||||||
|
|
||||||
|
def traverse_tree(self, bom_list=[]):
|
||||||
def _get_children(bom_no):
|
def _get_children(bom_no):
|
||||||
return [cstr(d[0]) for d in webnotes.conn.sql("""select bom_no from `tabBOM Item`
|
return [cstr(d[0]) for d in webnotes.conn.sql("""select bom_no from `tabBOM Item`
|
||||||
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
|
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
|
||||||
|
|
||||||
bom_list, count = [self.doc.name], 0
|
count = 0
|
||||||
|
if self.doc.name not in bom_list:
|
||||||
|
bom_list.append(self.doc.name)
|
||||||
|
|
||||||
while(count < len(bom_list)):
|
while(count < len(bom_list)):
|
||||||
for child_bom in _get_children(bom_list[count]):
|
for child_bom in _get_children(bom_list[count]):
|
||||||
if child_bom not in bom_list:
|
if child_bom not in bom_list:
|
||||||
@ -325,52 +330,50 @@ class DocType:
|
|||||||
|
|
||||||
def get_exploded_items(self):
|
def get_exploded_items(self):
|
||||||
""" Get all raw materials including items from child bom"""
|
""" Get all raw materials including items from child bom"""
|
||||||
self.cur_exploded_items = []
|
self.cur_exploded_items = {}
|
||||||
for d in getlist(self.doclist, 'bom_materials'):
|
for d in getlist(self.doclist, 'bom_materials'):
|
||||||
if d.bom_no:
|
if d.bom_no:
|
||||||
self.get_child_exploded_items(d.bom_no, d.qty)
|
self.get_child_exploded_items(d.bom_no, d.qty)
|
||||||
else:
|
else:
|
||||||
self.cur_exploded_items.append({
|
self.add_to_cur_exploded_items(webnotes._dict({
|
||||||
'item_code' : d.item_code,
|
'item_code' : d.item_code,
|
||||||
'description' : d.description,
|
'description' : d.description,
|
||||||
'stock_uom' : d.stock_uom,
|
'stock_uom' : d.stock_uom,
|
||||||
'qty' : flt(d.qty),
|
'qty' : flt(d.qty),
|
||||||
'rate' : flt(d.rate),
|
'rate' : flt(d.rate),
|
||||||
'amount' : flt(d.amount),
|
}))
|
||||||
'parent_bom' : d.parent,
|
|
||||||
'mat_detail_no' : d.name,
|
def add_to_cur_exploded_items(self, args):
|
||||||
'qty_consumed_per_unit' : flt(d.qty_consumed_per_unit)
|
if self.cur_exploded_items.get(args.item_code):
|
||||||
})
|
self.cur_exploded_items[args.item_code]["qty"] += args.qty
|
||||||
|
else:
|
||||||
|
self.cur_exploded_items[args.item_code] = args
|
||||||
|
|
||||||
def get_child_exploded_items(self, bom_no, qty):
|
def get_child_exploded_items(self, bom_no, qty):
|
||||||
""" Add all items from Flat BOM of child BOM"""
|
""" Add all items from Flat BOM of child BOM"""
|
||||||
|
|
||||||
child_fb_items = sql("""select item_code, description, stock_uom, qty, rate,
|
child_fb_items = sql("""select item_code, description, stock_uom, qty, rate,
|
||||||
amount, parent_bom, mat_detail_no, qty_consumed_per_unit
|
qty_consumed_per_unit from `tabBOM Explosion Item`
|
||||||
from `tabBOM Explosion Item` where parent = '%s' and docstatus = 1""" %
|
where parent = %s and docstatus = 1""", bom_no, as_dict = 1)
|
||||||
bom_no, as_dict = 1)
|
|
||||||
for d in child_fb_items:
|
for d in child_fb_items:
|
||||||
self.cur_exploded_items.append({
|
self.add_to_cur_exploded_items(webnotes._dict({
|
||||||
'item_code' : d['item_code'],
|
'item_code' : d['item_code'],
|
||||||
'description' : d['description'],
|
'description' : d['description'],
|
||||||
'stock_uom' : d['stock_uom'],
|
'stock_uom' : d['stock_uom'],
|
||||||
'qty' : flt(d['qty_consumed_per_unit'])*qty,
|
'qty' : flt(d['qty_consumed_per_unit'])*qty,
|
||||||
'rate' : flt(d['rate']),
|
'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)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
def add_exploded_items(self):
|
def add_exploded_items(self):
|
||||||
"Add items to Flat BOM table"
|
"Add items to Flat BOM table"
|
||||||
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
|
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
|
||||||
for d in self.cur_exploded_items:
|
for d in self.cur_exploded_items:
|
||||||
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item',
|
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', self.doclist)
|
||||||
self.doclist)
|
for i in self.cur_exploded_items[d].keys():
|
||||||
for i in d.keys():
|
ch.fields[i] = self.cur_exploded_items[d][i]
|
||||||
ch.fields[i] = d[i]
|
ch.amount = flt(ch.qty) * flt(ch.rate)
|
||||||
|
ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.doc.quantity)
|
||||||
ch.docstatus = self.doc.docstatus
|
ch.docstatus = self.doc.docstatus
|
||||||
ch.save(1)
|
ch.save(1)
|
||||||
|
|
||||||
|
@ -48,134 +48,4 @@ test_records = [
|
|||||||
"stock_uom": "No."
|
"stock_uom": "No."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# import webnotes.model
|
|
||||||
# from webnotes.utils import nowdate, flt
|
|
||||||
# from accounts.utils import get_fiscal_year
|
|
||||||
# from webnotes.model.doclist import DocList
|
|
||||||
# import copy
|
|
||||||
#
|
|
||||||
# company = webnotes.conn.get_default("company")
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def load_data():
|
|
||||||
#
|
|
||||||
# # create default warehouse
|
|
||||||
# if not webnotes.conn.exists("Warehouse", "Default Warehouse"):
|
|
||||||
# webnotes.insert({"doctype": "Warehouse",
|
|
||||||
# "warehouse_name": "Default Warehouse",
|
|
||||||
# "warehouse_type": "Stores"})
|
|
||||||
#
|
|
||||||
# # create UOM: Nos.
|
|
||||||
# if not webnotes.conn.exists("UOM", "Nos"):
|
|
||||||
# webnotes.insert({"doctype": "UOM", "uom_name": "Nos"})
|
|
||||||
#
|
|
||||||
# from webnotes.tests import insert_test_data
|
|
||||||
# # create item groups and items
|
|
||||||
# insert_test_data("Item Group",
|
|
||||||
# sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name')))
|
|
||||||
# insert_test_data("Item")
|
|
||||||
#
|
|
||||||
# base_bom_fg = [
|
|
||||||
# {"doctype": "BOM", "item": "Android Jack D", "quantity": 1,
|
|
||||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
|
||||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
|
||||||
# "opn_description": "Development", "hour_rate": 10, "time_in_mins": 90},
|
|
||||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1,
|
|
||||||
# "qty": 2, "rate": 20, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
|
||||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 100", "operation_no": 1,
|
|
||||||
# "qty": 1, "rate": 300, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
|
||||||
# {"doctype": "BOM Item", "item_code": "Nebula 7", "operation_no": 1,
|
|
||||||
# "qty": 5, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# base_bom_child = [
|
|
||||||
# {"doctype": "BOM", "item": "Nebula 7", "quantity": 5,
|
|
||||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
|
||||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
|
||||||
# "opn_description": "Development"},
|
|
||||||
# {"doctype": "BOM Item", "item_code": "Android Jack S", "operation_no": 1,
|
|
||||||
# "qty": 10, "stock_uom": "Nos", "parentfield": "bom_materials"}
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# base_bom_grandchild = [
|
|
||||||
# {"doctype": "BOM", "item": "Android Jack S", "quantity": 1,
|
|
||||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
|
||||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
|
||||||
# "opn_description": "Development"},
|
|
||||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1,
|
|
||||||
# "qty": 3, "rate": 10, "stock_uom": "Nos", "parentfield": "bom_materials"}
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class TestPurchaseReceipt(unittest.TestCase):
|
|
||||||
# def setUp(self):
|
|
||||||
# webnotes.conn.begin()
|
|
||||||
# load_data()
|
|
||||||
#
|
|
||||||
# def test_bom_validation(self):
|
|
||||||
# # show throw error bacause bom no missing for sub-assembly item
|
|
||||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
|
||||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
|
||||||
#
|
|
||||||
# # main item is not a manufacturing item
|
|
||||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
|
||||||
# bom_fg[0]["item"] = "Home Desktop 200"
|
|
||||||
# bom_fg.pop(4)
|
|
||||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
|
||||||
#
|
|
||||||
# # operation no mentioed in material table not matching with operation table
|
|
||||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
|
||||||
# bom_fg.pop(4)
|
|
||||||
# bom_fg[2]["operation_no"] = 2
|
|
||||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def test_bom(self):
|
|
||||||
# gc_wrapper = webnotes.insert(DocList(base_bom_grandchild))
|
|
||||||
# gc_wrapper.submit()
|
|
||||||
#
|
|
||||||
# bom_child = copy.deepcopy(base_bom_child)
|
|
||||||
# bom_child[2]["bom_no"] = gc_wrapper.doc.name
|
|
||||||
# child_wrapper = webnotes.insert(DocList(bom_child))
|
|
||||||
# child_wrapper.submit()
|
|
||||||
#
|
|
||||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
|
||||||
# bom_fg[4]["bom_no"] = child_wrapper.doc.name
|
|
||||||
# fg_wrapper = webnotes.insert(DocList(bom_fg))
|
|
||||||
# fg_wrapper.load_from_db()
|
|
||||||
#
|
|
||||||
# self.check_bom_cost(fg_wrapper)
|
|
||||||
#
|
|
||||||
# self.check_flat_bom(fg_wrapper, child_wrapper, gc_wrapper)
|
|
||||||
#
|
|
||||||
# def check_bom_cost(self, fg_wrapper):
|
|
||||||
# expected_values = {
|
|
||||||
# "operating_cost": 15,
|
|
||||||
# "raw_material_cost": 640,
|
|
||||||
# "total_cost": 655
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# for key in expected_values:
|
|
||||||
# self.assertEqual(flt(expected_values[key]), flt(fg_wrapper.doc.fields.get(key)))
|
|
||||||
#
|
|
||||||
# def check_flat_bom(self, fg_wrapper, child_wrapper, gc_wrapper):
|
|
||||||
# expected_flat_bom_items = {
|
|
||||||
# ("Home Desktop 300", fg_wrapper.doc.name): (2, 20),
|
|
||||||
# ("Home Desktop 100", fg_wrapper.doc.name): (1, 300),
|
|
||||||
# ("Home Desktop 300", gc_wrapper.doc.name): (30, 10)
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# self.assertEqual(len(fg_wrapper.doclist.get({"parentfield": "flat_bom_details"})), 3)
|
|
||||||
#
|
|
||||||
# for key, val in expected_flat_bom_items.items():
|
|
||||||
# flat_bom = fg_wrapper.doclist.get({"parentfield": "flat_bom_details",
|
|
||||||
# "item_code": key[0], "parent_bom": key[1]})[0]
|
|
||||||
# self.assertEqual(val, (flat_bom.qty, flat_bom.rate))
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def tearDown(self):
|
|
||||||
# webnotes.conn.rollback()
|
|
@ -1,8 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"creation": "2013-02-22 01:27:48",
|
"creation": "2013-03-07 11:42:57",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-03-07 07:03:18",
|
"modified": "2013-06-04 13:13:28",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -80,25 +80,6 @@
|
|||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "UOM"
|
"options": "UOM"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "parent_bom",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"label": "Parent BOM",
|
|
||||||
"oldfieldname": "parent_bom",
|
|
||||||
"oldfieldtype": "Link",
|
|
||||||
"options": "BOM",
|
|
||||||
"print_width": "250px",
|
|
||||||
"width": "250px"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "mat_detail_no",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1,
|
|
||||||
"label": "Mat Detail No"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "qty_consumed_per_unit",
|
"fieldname": "qty_consumed_per_unit",
|
||||||
|
@ -29,9 +29,10 @@ class DocType:
|
|||||||
self.validate_bom()
|
self.validate_bom()
|
||||||
self.update_new_bom()
|
self.update_new_bom()
|
||||||
bom_list = self.get_parent_boms()
|
bom_list = self.get_parent_boms()
|
||||||
|
updated_bom = []
|
||||||
for bom in bom_list:
|
for bom in bom_list:
|
||||||
bom_obj = get_obj("BOM", bom, with_children=1)
|
bom_obj = get_obj("BOM", bom, with_children=1)
|
||||||
bom_obj.update_cost_and_exploded_items()
|
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
|
||||||
|
|
||||||
webnotes.msgprint(_("BOM replaced"))
|
webnotes.msgprint(_("BOM replaced"))
|
||||||
|
|
||||||
|
@ -241,40 +241,30 @@ class DocType:
|
|||||||
def get_raw_materials(self, bom_dict):
|
def get_raw_materials(self, bom_dict):
|
||||||
""" Get raw materials considering sub-assembly items
|
""" Get raw materials considering sub-assembly items
|
||||||
{
|
{
|
||||||
"item_code": [qty_required, description, stock_uom]
|
"item_code": [qty_required, description, stock_uom, min_order_qty]
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
for bom in bom_dict:
|
for bom in bom_dict:
|
||||||
if self.doc.use_multi_level_bom:
|
if self.doc.use_multi_level_bom:
|
||||||
# get all raw materials with sub assembly childs
|
# get all raw materials with sub assembly childs
|
||||||
fl_bom_items = sql("""
|
fl_bom_items = sql("""select fb.item_code,
|
||||||
select
|
ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
|
||||||
item_code,ifnull(sum(qty_consumed_per_unit),0)*%s as qty,
|
fb.description, fb.stock_uom, it.min_order_qty
|
||||||
description, stock_uom, min_order_qty
|
from `tabBOM Explosion Item` fb,`tabItem` it
|
||||||
from
|
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
||||||
(
|
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
|
||||||
select distinct fb.name, fb.description, fb.item_code,
|
and fb.docstatus<2 and fb.parent=%s
|
||||||
fb.qty_consumed_per_unit, fb.stock_uom, it.min_order_qty
|
group by item_code, stock_uom""", (flt(bom_dict[bom]), bom))
|
||||||
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))
|
|
||||||
else:
|
else:
|
||||||
# Get all raw materials considering SA items as raw materials,
|
# Get all raw materials considering SA items as raw materials,
|
||||||
# so no childs of SA items
|
# so no childs of SA items
|
||||||
fl_bom_items = sql("""
|
fl_bom_items = sql("""select bom_item.item_code,
|
||||||
select bom_item.item_code,
|
|
||||||
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
|
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
|
||||||
bom_item.description, bom_item.stock_uom, item.min_order_qty
|
bom_item.description, bom_item.stock_uom, item.min_order_qty
|
||||||
from `tabBOM Item` bom_item, tabItem item
|
from `tabBOM Item` bom_item, tabItem item
|
||||||
where bom_item.parent = %s and bom_item.docstatus < 2
|
where bom_item.parent = %s and bom_item.docstatus < 2
|
||||||
and bom_item.item_code = item.name
|
and bom_item.item_code = item.name
|
||||||
group by item_code
|
group by item_code""", (flt(bom_dict[bom]), bom))
|
||||||
""", (flt(bom_dict[bom]), bom))
|
|
||||||
self.make_items_dict(fl_bom_items)
|
self.make_items_dict(fl_bom_items)
|
||||||
|
|
||||||
def make_items_dict(self, item_list):
|
def make_items_dict(self, item_list):
|
||||||
|
0
patches/june_2013/__init__.py
Normal file
0
patches/june_2013/__init__.py
Normal file
29
patches/june_2013/p01_update_bom_exploded_items.py
Normal file
29
patches/june_2013/p01_update_bom_exploded_items.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
updated_bom = []
|
||||||
|
for bom in webnotes.conn.sql("select name from tabBOM where docstatus < 2"):
|
||||||
|
if bom[0] not in updated_bom:
|
||||||
|
try:
|
||||||
|
bom_obj = webnotes.get_obj("BOM", bom[0], with_children=1)
|
||||||
|
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
|
||||||
|
webnotes.conn.commit()
|
||||||
|
except:
|
||||||
|
pass
|
@ -252,4 +252,6 @@ patch_list = [
|
|||||||
"patches.may_2013.p03_update_support_ticket",
|
"patches.may_2013.p03_update_support_ticket",
|
||||||
"patches.may_2013.p04_reorder_level",
|
"patches.may_2013.p04_reorder_level",
|
||||||
"patches.may_2013.p05_update_cancelled_gl_entries",
|
"patches.may_2013.p05_update_cancelled_gl_entries",
|
||||||
|
"patches.june_2013.p01_update_bom_exploded_items",
|
||||||
|
"execute:webnotes.delete_doc('DocType', 'System Console')",
|
||||||
]
|
]
|
@ -506,17 +506,13 @@ class DocType(StockController):
|
|||||||
|
|
||||||
if self.doc.use_multi_level_bom:
|
if self.doc.use_multi_level_bom:
|
||||||
# get all raw materials with sub assembly childs
|
# get all raw materials with sub assembly childs
|
||||||
fl_bom_sa_child_item = sql("""select
|
fl_bom_sa_child_item = sql("""select fb.item_code,
|
||||||
item_code,ifnull(sum(qty_consumed_per_unit),0)*%s as qty,
|
ifnull(sum(fb.qty_consumed_per_unit),0)*%s as qty, fb.description, fb.stock_uom
|
||||||
description,stock_uom
|
from `tabBOM Explosion Item` fb,`tabItem` it
|
||||||
from ( select distinct fb.name, fb.description, fb.item_code,
|
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
||||||
fb.qty_consumed_per_unit, fb.stock_uom
|
and ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus < 2
|
||||||
from `tabBOM Explosion Item` fb,`tabItem` it
|
and fb.parent=%s group by item_code, stock_uom""",
|
||||||
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
(qty, self.doc.bom_no), as_dict=1)
|
||||||
and ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus<2
|
|
||||||
and fb.parent=%s
|
|
||||||
) a
|
|
||||||
group by item_code, stock_uom""" , (qty, self.doc.bom_no), as_dict=1)
|
|
||||||
|
|
||||||
if fl_bom_sa_child_item:
|
if fl_bom_sa_child_item:
|
||||||
_make_items_dict(fl_bom_sa_child_item)
|
_make_items_dict(fl_bom_sa_child_item)
|
||||||
@ -524,10 +520,10 @@ class DocType(StockController):
|
|||||||
# Get all raw materials considering multi level BOM,
|
# Get all raw materials considering multi level BOM,
|
||||||
# if multi level bom consider childs of Sub-Assembly items
|
# if multi level bom consider childs of Sub-Assembly items
|
||||||
fl_bom_sa_items = sql("""select item_code,
|
fl_bom_sa_items = sql("""select item_code,
|
||||||
ifnull(sum(qty_consumed_per_unit), 0) * '%s' as qty,
|
ifnull(sum(qty_consumed_per_unit), 0) *%s as qty,
|
||||||
description, stock_uom from `tabBOM Item`
|
description, stock_uom from `tabBOM Item`
|
||||||
where parent = '%s' and docstatus < 2
|
where parent = %s and docstatus < 2
|
||||||
group by item_code""" % (qty, self.doc.bom_no), as_dict=1)
|
group by item_code""", (qty, self.doc.bom_no), as_dict=1)
|
||||||
|
|
||||||
if fl_bom_sa_items:
|
if fl_bom_sa_items:
|
||||||
_make_items_dict(fl_bom_sa_items)
|
_make_items_dict(fl_bom_sa_items)
|
||||||
|
@ -205,6 +205,19 @@ wn.module_page["Stock"] = [
|
|||||||
"label":wn._("Requested Items To Be Transferred"),
|
"label":wn._("Requested Items To Be Transferred"),
|
||||||
route: "query-report/Requested Items To Be Transferred",
|
route: "query-report/Requested Items To Be Transferred",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label":wn._("Batch-Wise Balance History"),
|
||||||
|
route: "query-report/Batch-Wise Balance History",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":wn._("Warehouse-Wise Stock Balance"),
|
||||||
|
route: "query-report/Warehouse-Wise Stock Balance",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":wn._("Item Prices"),
|
||||||
|
route: "query-report/Item Prices",
|
||||||
|
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label":wn._("Itemwise Recommended Reorder Level"),
|
"label":wn._("Itemwise Recommended Reorder Level"),
|
||||||
route: "query-report/Itemwise Recommended Reorder Level",
|
route: "query-report/Itemwise Recommended Reorder Level",
|
||||||
|
0
stock/report/batch_wise_balance_history/__init__.py
Normal file
0
stock/report/batch_wise_balance_history/__init__.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
wn.query_reports["Batch-Wise Balance History"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"item_code",
|
||||||
|
"label": "Item",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"warehouse",
|
||||||
|
"label": "Warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Warehouse",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"batch_no",
|
||||||
|
"label": "Batch",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Batch",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"from_date",
|
||||||
|
"label": "From Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": "80",
|
||||||
|
"default": sys_defaults.year_start_date,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"to_date",
|
||||||
|
"label": "To Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": "80",
|
||||||
|
"default": wn.datetime.get_today()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
# 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 flt
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
columns = get_columns(filters)
|
||||||
|
item_map = get_item_details(filters)
|
||||||
|
iwb_map = get_item_warehouse_batch_map(filters)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for item in sorted(iwb_map):
|
||||||
|
for wh in sorted(iwb_map[item]):
|
||||||
|
for batch in sorted(iwb_map[item][wh]):
|
||||||
|
qty_dict = iwb_map[item][wh][batch]
|
||||||
|
data.append([item, item_map[item]["item_name"],
|
||||||
|
item_map[item]["description"], wh, batch,
|
||||||
|
qty_dict.opening_qty, qty_dict.in_qty,
|
||||||
|
qty_dict.out_qty, qty_dict.bal_qty
|
||||||
|
])
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
"""return columns based on filters"""
|
||||||
|
|
||||||
|
columns = ["Item:Link/Item:100"] + ["Item Name::150"] + ["Description::150"] + \
|
||||||
|
["Warehouse:Link/Warehouse:100"] + ["Batch:Link/Batch:100"] + ["Opening Qty::90"] + \
|
||||||
|
["In Qty::80"] + ["Out Qty::80"] + ["Balance Qty::90"]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_conditions(filters):
|
||||||
|
conditions = ""
|
||||||
|
if filters.get("item_code"):
|
||||||
|
conditions += " and item_code='%s'" % filters["item_code"]
|
||||||
|
|
||||||
|
if filters.get("warehouse"):
|
||||||
|
conditions += " and warehouse='%s'" % filters["warehouse"]
|
||||||
|
|
||||||
|
if filters.get("batch_no"):
|
||||||
|
conditions += " and batch_no='%s'" % filters["batch_no"]
|
||||||
|
|
||||||
|
if not filters.get("from_date"):
|
||||||
|
webnotes.msgprint("Please enter From Date", raise_exception=1)
|
||||||
|
|
||||||
|
if filters.get("to_date"):
|
||||||
|
conditions += " and posting_date <= '%s'" % filters["to_date"]
|
||||||
|
else:
|
||||||
|
webnotes.msgprint("Please enter To Date", raise_exception=1)
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
#get all details
|
||||||
|
def get_stock_ledger_entries(filters):
|
||||||
|
conditions = get_conditions(filters)
|
||||||
|
return webnotes.conn.sql("""select item_code, batch_no, warehouse,
|
||||||
|
posting_date, actual_qty
|
||||||
|
from `tabStock Ledger Entry`
|
||||||
|
where ifnull(is_cancelled, 'No') = 'No' %s order by item_code, warehouse""" %
|
||||||
|
conditions, as_dict=1)
|
||||||
|
|
||||||
|
def get_item_warehouse_batch_map(filters):
|
||||||
|
sle = get_stock_ledger_entries(filters)
|
||||||
|
iwb_map = {}
|
||||||
|
|
||||||
|
for d in sle:
|
||||||
|
iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, {})\
|
||||||
|
.setdefault(d.batch_no, webnotes._dict({
|
||||||
|
"opening_qty": 0.0, "in_qty": 0.0, "out_qty": 0.0, "bal_qty": 0.0
|
||||||
|
}))
|
||||||
|
qty_dict = iwb_map[d.item_code][d.warehouse][d.batch_no]
|
||||||
|
if d.posting_date < filters["from_date"]:
|
||||||
|
qty_dict.opening_qty += flt(d.actual_qty)
|
||||||
|
elif d.posting_date >= filters["from_date"] and d.posting_date <= filters["to_date"]:
|
||||||
|
if flt(d.actual_qty) > 0:
|
||||||
|
qty_dict.in_qty += flt(d.actual_qty)
|
||||||
|
else:
|
||||||
|
qty_dict.out_qty += abs(flt(d.actual_qty))
|
||||||
|
|
||||||
|
qty_dict.bal_qty += flt(d.actual_qty)
|
||||||
|
|
||||||
|
return iwb_map
|
||||||
|
|
||||||
|
def get_item_details(filters):
|
||||||
|
if filters.get("item_code"):
|
||||||
|
conditions = " and name = '%s'" % filters["item_code"]
|
||||||
|
item_map = {}
|
||||||
|
for d in webnotes.conn.sql("select name, item_name, description from tabItem", as_dict=1):
|
||||||
|
item_map.setdefault(d.name, d)
|
||||||
|
|
||||||
|
return item_map
|
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"creation": "2013-06-04 11:03:47",
|
||||||
|
"docstatus": 0,
|
||||||
|
"modified": "2013-06-04 19:32:27",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"owner": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"name": "__common__",
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Batch-Wise Balance History",
|
||||||
|
"report_type": "Script Report"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"name": "Batch-Wise Balance History"
|
||||||
|
}
|
||||||
|
]
|
0
stock/report/item_prices/__init__.py
Normal file
0
stock/report/item_prices/__init__.py
Normal file
106
stock/report/item_prices/item_prices.py
Normal file
106
stock/report/item_prices/item_prices.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# 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 flt
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
columns = get_columns(filters)
|
||||||
|
item_map = get_item_details()
|
||||||
|
pl = get_price_list()
|
||||||
|
bom_rate = get_item_bom_rate()
|
||||||
|
val_rate_map = get_valuation_rate()
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for item in sorted(item_map):
|
||||||
|
data.append([item, item_map[item]["item_name"],
|
||||||
|
item_map[item]["description"], item_map[item]["stock_uom"],
|
||||||
|
flt(item_map[item]["last_purchase_rate"]), val_rate_map.get(item, 0),
|
||||||
|
pl.get(item, {}).get("selling"), pl.get(item, {}).get("buying"),
|
||||||
|
bom_rate.get(item, 0), flt(item_map[item]["standard_rate"])
|
||||||
|
])
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
"""return columns based on filters"""
|
||||||
|
|
||||||
|
columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80",
|
||||||
|
"Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80", "Sales Price List::80",
|
||||||
|
"Purchase Price List::80", "BOM Rate:Currency:90", "Standard Rate:Currency:100"]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_item_details():
|
||||||
|
"""returns all items details"""
|
||||||
|
|
||||||
|
item_map = {}
|
||||||
|
|
||||||
|
for i in webnotes.conn.sql("select name, item_name, description, \
|
||||||
|
stock_uom, standard_rate, last_purchase_rate from tabItem \
|
||||||
|
order by item_code", as_dict=1):
|
||||||
|
item_map.setdefault(i.name, i)
|
||||||
|
|
||||||
|
return item_map
|
||||||
|
|
||||||
|
def get_price_list():
|
||||||
|
"""Get selling & buying price list of every item"""
|
||||||
|
|
||||||
|
rate = {}
|
||||||
|
|
||||||
|
price_list = webnotes.conn.sql("""select parent, selling, buying,
|
||||||
|
concat(price_list_name, " - ", ref_currency, " ", ref_rate) as price
|
||||||
|
from `tabItem Price` where docstatus<2""", as_dict=1)
|
||||||
|
|
||||||
|
for j in price_list:
|
||||||
|
if j.selling:
|
||||||
|
rate.setdefault(j.parent, {}).setdefault("selling", []).append(j.price)
|
||||||
|
if j.buying:
|
||||||
|
rate.setdefault(j.parent, {}).setdefault("buying", []).append(j.price)
|
||||||
|
|
||||||
|
item_rate_map = {}
|
||||||
|
|
||||||
|
for item in rate:
|
||||||
|
item_rate_map.setdefault(item, {}).setdefault("selling",
|
||||||
|
", ".join(rate[item].get("selling", [])))
|
||||||
|
item_rate_map[item]["buying"] = ", ".join(rate[item].get("buying", []))
|
||||||
|
|
||||||
|
return item_rate_map
|
||||||
|
|
||||||
|
def get_item_bom_rate():
|
||||||
|
"""Get BOM rate of an item from BOM"""
|
||||||
|
|
||||||
|
bom_map = {}
|
||||||
|
|
||||||
|
for b in webnotes.conn.sql("""select item, (total_cost/quantity) as bom_rate
|
||||||
|
from `tabBOM` where is_active=1 and is_default=1""", as_dict=1):
|
||||||
|
bom_map.setdefault(b.item, flt(b.bom_rate))
|
||||||
|
|
||||||
|
return bom_map
|
||||||
|
|
||||||
|
def get_valuation_rate():
|
||||||
|
"""Get an average valuation rate of an item from all warehouses"""
|
||||||
|
|
||||||
|
val_rate_map = {}
|
||||||
|
|
||||||
|
for d in webnotes.conn.sql("""select item_code, avg(valuation_rate) as val_rate
|
||||||
|
from tabBin group by item_code""", as_dict=1):
|
||||||
|
val_rate_map.setdefault(d.item_code, d.val_rate)
|
||||||
|
|
||||||
|
return val_rate_map
|
21
stock/report/item_prices/item_prices.txt
Normal file
21
stock/report/item_prices/item_prices.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"creation": "2013-06-05 11:43:30",
|
||||||
|
"docstatus": 0,
|
||||||
|
"modified": "2013-06-05 11:43:30",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"owner": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"name": "__common__",
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Item Prices",
|
||||||
|
"report_type": "Script Report"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"name": "Item Prices"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,32 @@
|
|||||||
|
wn.query_reports["Warehouse-Wise Stock Balance"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"item_code",
|
||||||
|
"label": "Item",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"warehouse",
|
||||||
|
"label": "Warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Warehouse",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"from_date",
|
||||||
|
"label": "From Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": "80",
|
||||||
|
"default": sys_defaults.year_start_date,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"to_date",
|
||||||
|
"label": "To Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": "80",
|
||||||
|
"default": wn.datetime.get_today()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
# 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 flt
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
columns = get_columns(filters)
|
||||||
|
item_map = get_item_details(filters)
|
||||||
|
iwb_map = get_item_warehouse_map(filters)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for item in sorted(iwb_map):
|
||||||
|
for wh in sorted(iwb_map[item]):
|
||||||
|
qty_dict = iwb_map[item][wh]
|
||||||
|
data.append([item, item_map[item]["item_name"],
|
||||||
|
item_map[item]["description"], wh,
|
||||||
|
qty_dict.opening_qty, qty_dict.in_qty,
|
||||||
|
qty_dict.out_qty, qty_dict.bal_qty
|
||||||
|
])
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
"""return columns based on filters"""
|
||||||
|
|
||||||
|
columns = ["Item:Link/Item:100"] + ["Item Name::150"] + ["Description::150"] + \
|
||||||
|
["Warehouse:Link/Warehouse:100"] + ["Opening Qty::90"] + \
|
||||||
|
["In Qty::80"] + ["Out Qty::80"] + ["Balance Qty::90"]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_conditions(filters):
|
||||||
|
conditions = ""
|
||||||
|
if filters.get("item_code"):
|
||||||
|
conditions += " and item_code='%s'" % filters["item_code"]
|
||||||
|
|
||||||
|
if filters.get("warehouse"):
|
||||||
|
conditions += " and warehouse='%s'" % filters["warehouse"]
|
||||||
|
|
||||||
|
if not filters.get("from_date"):
|
||||||
|
webnotes.msgprint("Please enter From Date", raise_exception=1)
|
||||||
|
|
||||||
|
if filters.get("to_date"):
|
||||||
|
conditions += " and posting_date <= '%s'" % filters["to_date"]
|
||||||
|
else:
|
||||||
|
webnotes.msgprint("Please enter To Date", raise_exception=1)
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
|
||||||
|
#get all details
|
||||||
|
def get_stock_ledger_entries(filters):
|
||||||
|
conditions = get_conditions(filters)
|
||||||
|
return webnotes.conn.sql("""select item_code, warehouse,
|
||||||
|
posting_date, actual_qty
|
||||||
|
from `tabStock Ledger Entry`
|
||||||
|
where ifnull(is_cancelled, 'No') = 'No' %s order by item_code, warehouse""" %
|
||||||
|
conditions, as_dict=1)
|
||||||
|
|
||||||
|
def get_item_warehouse_map(filters):
|
||||||
|
sle = get_stock_ledger_entries(filters)
|
||||||
|
iwb_map = {}
|
||||||
|
|
||||||
|
for d in sle:
|
||||||
|
iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, webnotes._dict({\
|
||||||
|
"opening_qty": 0.0, "in_qty": 0.0, "out_qty": 0.0, "bal_qty": 0.0
|
||||||
|
}))
|
||||||
|
qty_dict = iwb_map[d.item_code][d.warehouse]
|
||||||
|
if d.posting_date < filters["from_date"]:
|
||||||
|
qty_dict.opening_qty += flt(d.actual_qty)
|
||||||
|
elif d.posting_date >= filters["from_date"] and d.posting_date <= filters["to_date"]:
|
||||||
|
if flt(d.actual_qty) > 0:
|
||||||
|
qty_dict.in_qty += flt(d.actual_qty)
|
||||||
|
else:
|
||||||
|
qty_dict.out_qty += abs(flt(d.actual_qty))
|
||||||
|
|
||||||
|
qty_dict.bal_qty += flt(d.actual_qty)
|
||||||
|
|
||||||
|
return iwb_map
|
||||||
|
|
||||||
|
def get_item_details(filters):
|
||||||
|
if filters.get("item_code"):
|
||||||
|
conditions = " and name = '%s'" % filters["item_code"]
|
||||||
|
item_map = {}
|
||||||
|
for d in webnotes.conn.sql("select name, item_name, description from tabItem", as_dict=1):
|
||||||
|
item_map.setdefault(d.name, d)
|
||||||
|
|
||||||
|
return item_map
|
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"creation": "2013-06-05 11:00:31",
|
||||||
|
"docstatus": 0,
|
||||||
|
"modified": "2013-06-05 11:00:31",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"owner": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"name": "__common__",
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Warehouse-Wise Stock Balance",
|
||||||
|
"report_type": "Script Report"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Report",
|
||||||
|
"name": "Warehouse-Wise Stock Balance"
|
||||||
|
}
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user