[merge conflict]
diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py
index 429cc10..112e449 100644
--- a/accounts/doctype/gl_entry/gl_entry.py
+++ b/accounts/doctype/gl_entry/gl_entry.py
@@ -42,9 +42,9 @@
self.check_negative_balance(adv_adj)
# Update outstanding amt on against voucher
- if self.doc.against_voucher and self.doc.against_voucher_type not in \
- ('Journal Voucher','POS') and update_outstanding == 'Yes':
- self.update_outstanding_amt()
+ if self.doc.against_voucher and self.doc.against_voucher_type != "POS" \
+ and update_outstanding == 'Yes':
+ self.update_outstanding_amt()
def check_mandatory(self):
mandatory = ['account','remarks','voucher_type','voucher_no','fiscal_year','company']
@@ -164,16 +164,25 @@
and ifnull(is_cancelled,'No') = 'No'""",
(self.doc.against_voucher, self.doc.against_voucher_type))[0][0] or 0.0)
- if self.doc.against_voucher_type=='Purchase Invoice':
- # amount to debit
+ if self.doc.against_voucher_type == 'Purchase Invoice':
bal = -bal
+ elif self.doc.against_voucher_type == "Journal Voucher":
+ against_voucher_amount = flt(webnotes.conn.sql("""select sum(debit) - sum(credit)
+ from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s
+ and account = %s""", (self.doc.against_voucher, self.doc.account))[0][0])
+
+ bal = against_voucher_amount + bal
+ if against_voucher_amount < 0:
+ bal = -bal
+
# Validation : Outstanding can not be negative
if bal < 0 and self.doc.is_cancelled == 'No':
msgprint(_("Outstanding for Voucher ") + self.doc.against_voucher +
- _(" will become ") + fmt_money(bal) + _("Outstanding cannot be less than zero. \
+ _(" will become ") + fmt_money(bal) + _(". Outstanding cannot be less than zero. \
Please match exact outstanding."), raise_exception=1)
# Update outstanding amt on against voucher
- sql("update `tab%s` set outstanding_amount=%s where name='%s'"%
- (self.doc.against_voucher_type, bal, self.doc.against_voucher))
\ No newline at end of file
+ if self.doc.against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
+ sql("update `tab%s` set outstanding_amount=%s where name='%s'"%
+ (self.doc.against_voucher_type, bal, self.doc.against_voucher))
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index c5fee16..17db651 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -340,17 +340,6 @@
from accounts.utils import reconcile_against_document
reconcile_against_document(lst)
- def validate_customer(self):
- """ Validate customer name with SO and DN"""
- for d in getlist(self.doclist,'entries'):
- dt = d.delivery_note and 'Delivery Note' or d.sales_order and 'Sales Order' or ''
- if dt:
- dt_no = d.delivery_note or d.sales_order
- cust = webnotes.conn.sql("select customer from `tab%s` where name = %s" % (dt, '%s'), dt_no)
- if cust and cstr(cust[0][0]) != cstr(self.doc.customer):
- msgprint("Customer %s does not match with customer of %s: %s." %(self.doc.customer, dt, dt_no), raise_exception=1)
-
-
def validate_customer_account(self):
"""Validates Debit To Account and Customer Matches"""
if self.doc.customer and self.doc.debit_to and not cint(self.doc.is_pos):
@@ -360,6 +349,19 @@
(not acc_head and (self.doc.debit_to != cstr(self.doc.customer) + " - " + self.get_company_abbr())):
msgprint("Debit To: %s do not match with Customer: %s for Company: %s.\n If both correctly entered, please select Master Type \
and Master Name in account master." %(self.doc.debit_to, self.doc.customer,self.doc.company), raise_exception=1)
+
+
+ def validate_customer(self):
+ """ Validate customer name with SO and DN"""
+ if self.doc.customer:
+ for d in getlist(self.doclist,'entries'):
+ dt = d.delivery_note and 'Delivery Note' or d.sales_order and 'Sales Order' or ''
+ if dt:
+ dt_no = d.delivery_note or d.sales_order
+ cust = webnotes.conn.get_value(dt, dt_no, "customer")
+ if cust and cstr(cust) != cstr(self.doc.customer):
+ msgprint("Customer %s does not match with customer of %s: %s."
+ %(self.doc.customer, dt, dt_no), raise_exception=1)
def validate_debit_acc(self):
diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js
index 25ee92c..0300902 100644
--- a/accounts/page/accounts_home/accounts_home.js
+++ b/accounts/page/accounts_home/accounts_home.js
@@ -128,6 +128,16 @@
icon: "icon-table",
items: [
{
+ "label":wn._("Customer Account Head"),
+ route: "query-report/Customer Account Head",
+ doctype: "Account"
+ },
+ {
+ "label":wn._("Supplier Account Head"),
+ route: "query-report/Supplier Account Head",
+ doctype: "Account"
+ },
+ {
"label":wn._("General Ledger"),
page: "general-ledger"
},
@@ -232,6 +242,16 @@
route: "query-report/Sales Partners Commission",
doctype: "Sales Invoice"
},
+ {
+ "label":wn._("Customer Account Head"),
+ route: "query-report/Customer Account Head",
+ doctype: "Account"
+ },
+ {
+ "label":wn._("Item-wise Sales Register"),
+ route: "query-report/Item-wise Sales Register",
+ doctype: "Sales Invoice"
+ },
]
}
]
diff --git a/accounts/report/customer_account_head/__init__.py b/accounts/report/customer_account_head/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/accounts/report/customer_account_head/__init__.py
diff --git a/accounts/report/customer_account_head/customer_account_head.py b/accounts/report/customer_account_head/customer_account_head.py
new file mode 100644
index 0000000..61f8cb2
--- /dev/null
+++ b/accounts/report/customer_account_head/customer_account_head.py
@@ -0,0 +1,49 @@
+# 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):
+ account_map = get_account_map()
+ columns = get_columns(account_map)
+ data = []
+ customers = webnotes.conn.sql("select name from tabCustomer where docstatus < 2")
+ for cust in customers:
+ row = [cust[0]]
+ for company in sorted(account_map):
+ row.append(account_map[company].get(cust[0], ''))
+ data.append(row)
+
+ return columns, data
+
+def get_account_map():
+ accounts = webnotes.conn.sql("""select name, company, master_name
+ from `tabAccount` where master_type = 'Customer'
+ and ifnull(master_name, '') != '' and docstatus < 2""", as_dict=1)
+
+ account_map = {}
+ for acc in accounts:
+ account_map.setdefault(acc.company, {}).setdefault(acc.master_name, {})
+ account_map[acc.company][acc.master_name] = acc.name
+
+ return account_map
+
+def get_columns(account_map):
+ columns = ["Customer:Link/Customer:120"] + \
+ [(company + ":Link/Account:120") for company in sorted(account_map)]
+
+ return columns
\ No newline at end of file
diff --git a/accounts/report/customer_account_head/customer_account_head.txt b/accounts/report/customer_account_head/customer_account_head.txt
new file mode 100644
index 0000000..d258fac
--- /dev/null
+++ b/accounts/report/customer_account_head/customer_account_head.txt
@@ -0,0 +1,21 @@
+[
+ {
+ "creation": "2013-06-03 16:17:34",
+ "docstatus": 0,
+ "modified": "2013-06-03 16:17:34",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "name": "__common__",
+ "ref_doctype": "Account",
+ "report_name": "Customer Account Head",
+ "report_type": "Script Report"
+ },
+ {
+ "doctype": "Report",
+ "name": "Customer Account Head"
+ }
+]
\ No newline at end of file
diff --git a/accounts/report/supplier_account_head/__init__.py b/accounts/report/supplier_account_head/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/accounts/report/supplier_account_head/__init__.py
diff --git a/accounts/report/supplier_account_head/supplier_account_head.py b/accounts/report/supplier_account_head/supplier_account_head.py
new file mode 100644
index 0000000..8b55067
--- /dev/null
+++ b/accounts/report/supplier_account_head/supplier_account_head.py
@@ -0,0 +1,49 @@
+# 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):
+ account_map = get_account_map()
+ columns = get_columns(account_map)
+ data = []
+ suppliers = webnotes.conn.sql("select name from tabSupplier where docstatus < 2")
+ for supplier in suppliers:
+ row = [supplier[0]]
+ for company in sorted(account_map):
+ row.append(account_map[company].get(supplier[0], ''))
+ data.append(row)
+
+ return columns, data
+
+def get_account_map():
+ accounts = webnotes.conn.sql("""select name, company, master_name
+ from `tabAccount` where master_type = 'Supplier'
+ and ifnull(master_name, '') != '' and docstatus < 2""", as_dict=1)
+
+ account_map = {}
+ for acc in accounts:
+ account_map.setdefault(acc.company, {}).setdefault(acc.master_name, {})
+ account_map[acc.company][acc.master_name] = acc.name
+
+ return account_map
+
+def get_columns(account_map):
+ columns = ["Supplier:Link/Supplier:120"] + \
+ [(company + ":Link/Account:120") for company in sorted(account_map)]
+
+ return columns
\ No newline at end of file
diff --git a/accounts/report/supplier_account_head/supplier_account_head.txt b/accounts/report/supplier_account_head/supplier_account_head.txt
new file mode 100644
index 0000000..b0554e8
--- /dev/null
+++ b/accounts/report/supplier_account_head/supplier_account_head.txt
@@ -0,0 +1,21 @@
+[
+ {
+ "creation": "2013-06-04 12:56:17",
+ "docstatus": 0,
+ "modified": "2013-06-04 12:56:46",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "name": "__common__",
+ "ref_doctype": "Account",
+ "report_name": "Supplier Account Head",
+ "report_type": "Script Report"
+ },
+ {
+ "doctype": "Report",
+ "name": "Supplier Account Head"
+ }
+]
\ No newline at end of file
diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py
index 5a1d47f..5f64148 100644
--- a/manufacturing/doctype/bom/bom.py
+++ b/manufacturing/doctype/bom/bom.py
@@ -266,22 +266,27 @@
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)
+ """ % (cstr(b[0]), cstr(d[2]), self.doc.name), raise_exception = 1)
if b[0]:
bom_list.append(b[0])
- def update_cost_and_exploded_items(self):
- bom_list = self.traverse_tree()
+ def update_cost_and_exploded_items(self, bom_list=[]):
+ bom_list = self.traverse_tree(bom_list)
for bom in bom_list:
bom_obj = get_obj("BOM", bom, with_children=1)
bom_obj.on_update()
- def traverse_tree(self):
+ return bom_list
+
+ def traverse_tree(self, bom_list=[]):
def _get_children(bom_no):
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)]
- 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)):
for child_bom in _get_children(bom_list[count]):
if child_bom not in bom_list:
@@ -325,52 +330,50 @@
def get_exploded_items(self):
""" 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'):
if d.bom_no:
self.get_child_exploded_items(d.bom_no, d.qty)
else:
- self.cur_exploded_items.append({
+ self.add_to_cur_exploded_items(webnotes._dict({
'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,
- 'mat_detail_no' : d.name,
- 'qty_consumed_per_unit' : flt(d.qty_consumed_per_unit)
- })
+ 'rate' : flt(d.rate),
+ }))
+
+ def add_to_cur_exploded_items(self, args):
+ 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):
""" 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)
+ 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_exploded_items.append({
+ self.add_to_cur_exploded_items(webnotes._dict({
'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)
-
- })
+ 'rate' : flt(d['rate']),
+ }))
def add_exploded_items(self):
"Add items to Flat BOM table"
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
for d in self.cur_exploded_items:
- ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item',
- self.doclist)
- for i in d.keys():
- ch.fields[i] = d[i]
+ ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', self.doclist)
+ for i in self.cur_exploded_items[d].keys():
+ ch.fields[i] = self.cur_exploded_items[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.save(1)
diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py
index e742c0c..cb91e78 100644
--- a/manufacturing/doctype/bom/test_bom.py
+++ b/manufacturing/doctype/bom/test_bom.py
@@ -48,134 +48,4 @@
"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()
\ No newline at end of file
+]
\ No newline at end of file
diff --git a/manufacturing/doctype/bom_explosion_item/bom_explosion_item.txt b/manufacturing/doctype/bom_explosion_item/bom_explosion_item.txt
index 07aad7d..3808cdf 100644
--- a/manufacturing/doctype/bom_explosion_item/bom_explosion_item.txt
+++ b/manufacturing/doctype/bom_explosion_item/bom_explosion_item.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-02-22 01:27:48",
+ "creation": "2013-03-07 11:42:57",
"docstatus": 0,
- "modified": "2013-03-07 07:03:18",
+ "modified": "2013-06-04 13:13:28",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -82,25 +82,6 @@
},
{
"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",
"fieldname": "qty_consumed_per_unit",
"fieldtype": "Float",
"hidden": 0,
diff --git a/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py b/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
index 4c9c42d..e69c487 100644
--- a/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
+++ b/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
@@ -29,9 +29,10 @@
self.validate_bom()
self.update_new_bom()
bom_list = self.get_parent_boms()
+ updated_bom = []
for bom in bom_list:
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"))
diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index 1686478..ed7f7bf 100644
--- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -241,40 +241,30 @@
def get_raw_materials(self, bom_dict):
""" 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:
if self.doc.use_multi_level_bom:
# 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, min_order_qty
- from
- (
- select distinct fb.name, fb.description, fb.item_code,
- fb.qty_consumed_per_unit, fb.stock_uom, it.min_order_qty
- 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))
+ fl_bom_items = sql("""select fb.item_code,
+ ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
+ fb.description, fb.stock_uom, it.min_order_qty
+ 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
+ group by item_code, stock_uom""", (flt(bom_dict[bom]), bom))
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
- fl_bom_items = sql("""
- select bom_item.item_code,
+ fl_bom_items = sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item
where bom_item.parent = %s and bom_item.docstatus < 2
- and bom_item.item_code = item.name
- group by item_code
- """, (flt(bom_dict[bom]), bom))
+ and bom_item.item_code = item.name
+ group by item_code""", (flt(bom_dict[bom]), bom))
self.make_items_dict(fl_bom_items)
def make_items_dict(self, item_list):
@@ -317,9 +307,9 @@
items_to_be_requested = webnotes._dict()
for item in self.item_dict:
- if flt(self.item_dict[item][0]) > item_projected_qty[item]:
+ if flt(self.item_dict[item][0]) > item_projected_qty.get(item, 0):
# shortage
- requested_qty = flt(self.item_dict[item][0]) - item_projected_qty[item]
+ requested_qty = flt(self.item_dict[item][0]) - item_projected_qty.get(item, 0)
# comsider minimum order qty
requested_qty = requested_qty > flt(self.item_dict[item][3]) and \
requested_qty or flt(self.item_dict[item][3])
@@ -379,4 +369,4 @@
webnotes.msgprint("Following Material Request created successfully: \n%s" %
"\n".join(pur_req))
else:
- webnotes.msgprint("Nothing to request")
\ No newline at end of file
+ webnotes.msgprint("Nothing to request")
diff --git a/patches/april_2013/p06_update_file_size.py b/patches/april_2013/p06_update_file_size.py
index 8709c7b..760c3cb 100644
--- a/patches/april_2013/p06_update_file_size.py
+++ b/patches/april_2013/p06_update_file_size.py
@@ -2,11 +2,13 @@
def execute():
files_path = webnotes.utils.get_path("public", "files")
+ webnotes.conn.auto_commit_on_many_writes = 1
+
for f in webnotes.conn.sql("""select name, file_name from
`tabFile Data`""", as_dict=True):
if f.file_name:
filepath = os.path.join(files_path, f.file_name)
if os.path.exists(filepath):
webnotes.conn.set_value("File Data", f.name, "file_size", os.stat(filepath).st_size)
-
-
\ No newline at end of file
+
+ webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
diff --git a/patches/april_2013/p07_update_file_data_2.py b/patches/april_2013/p07_update_file_data_2.py
index 0cb44d0..548ba6c 100644
--- a/patches/april_2013/p07_update_file_data_2.py
+++ b/patches/april_2013/p07_update_file_data_2.py
@@ -2,6 +2,8 @@
def execute():
from patches.april_2013.p05_update_file_data import update_file_list, get_single_doctypes
+ webnotes.conn.auto_commit_on_many_writes = 1
+
singles = get_single_doctypes()
for doctype in webnotes.conn.sql_list("""select table_name from `information_schema`.`columns`
where table_schema=%s and column_name='file_list'""", webnotes.conn.cur_db_name):
@@ -13,4 +15,5 @@
webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list'
and parent=%s""", doctype)
-
\ No newline at end of file
+
+ webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
diff --git a/patches/june_2013/__init__.py b/patches/june_2013/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/patches/june_2013/__init__.py
diff --git a/patches/june_2013/p01_update_bom_exploded_items.py b/patches/june_2013/p01_update_bom_exploded_items.py
new file mode 100644
index 0000000..eff0931
--- /dev/null
+++ b/patches/june_2013/p01_update_bom_exploded_items.py
@@ -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
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index e877b92..daf93f6 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -256,4 +256,5 @@
"patches.may_2013.p06_make_notes",
"patches.may_2013.p07_move_update_stock_to_pos",
"patches.may_2013.p08_change_item_wise_tax",
+ "patches.june_2013.p01_update_bom_exploded_items",
]
\ No newline at end of file
diff --git a/projects/page/projects_home/projects_home.js b/projects/page/projects_home/projects_home.js
index cfde6b3..fd13a67 100644
--- a/projects/page/projects_home/projects_home.js
+++ b/projects/page/projects_home/projects_home.js
@@ -60,6 +60,11 @@
route: "query-report/Daily Time Log Summary",
doctype: "Time Log"
},
+ {
+ "label":wn._("Project wise Stock Tracking"),
+ route: "query-report/Project wise Stock Tracking",
+ doctype: "Project"
+ },
]
}]
diff --git a/projects/report/project_wise_stock_tracking/__init__.py b/projects/report/project_wise_stock_tracking/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/projects/report/project_wise_stock_tracking/__init__.py
diff --git a/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py b/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
new file mode 100644
index 0000000..7c702e4
--- /dev/null
+++ b/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
@@ -0,0 +1,90 @@
+# 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/>.
+
+import webnotes
+
+def execute(filters=None):
+ columns = get_columns()
+ proj_details = get_project_details()
+ pr_item_map = get_purchased_items_cost()
+ se_item_map = get_issued_items_cost()
+ dn_item_map = get_delivered_items_cost()
+
+ data = []
+ for project in proj_details:
+ data.append([project.name, pr_item_map.get(project.name, 0),
+ se_item_map.get(project.name, 0), dn_item_map.get(project.name, 0),
+ project.project_name, project.status, project.company,
+ project.customer, project.project_value, project.project_start_date,
+ project.completion_date])
+
+ return columns, data
+
+def get_columns():
+ return ["Project Id:Link/Project:140", "Cost of Purchased Items:Currency:160",
+ "Cost of Issued Items:Currency:160", "Cost of Delivered Items:Currency:160",
+ "Project Name::120", "Project Status::120", "Company:Link/Company:100",
+ "Customer:Link/Customer:140", "Project Value:Currency:120",
+ "Project Start Date:Date:120", "Completion Date:Date:120"]
+
+def get_project_details():
+ return webnotes.conn.sql(""" select name, project_name, status, company, customer, project_value,
+ project_start_date, completion_date from tabProject where docstatus < 2""", as_dict=1)
+
+def get_purchased_items_cost():
+ pr_items = webnotes.conn.sql("""select project_name, sum(amount) as amount
+ from `tabPurchase Receipt Item` where ifnull(project_name, '') != ''
+ and docstatus = 1 group by project_name""", as_dict=1)
+
+ pr_item_map = {}
+ for item in pr_items:
+ pr_item_map.setdefault(item.project_name, item.amount)
+
+ return pr_item_map
+
+def get_issued_items_cost():
+ se_items = webnotes.conn.sql("""select se.project_name, sum(se_item.amount) as amount
+ from `tabStock Entry` se, `tabStock Entry Detail` se_item
+ where se.name = se_item.parent and se.docstatus = 1 and ifnull(se_item.t_warehouse, '') = ''
+ and ifnull(se.project_name, '') != '' group by se.project_name""", as_dict=1)
+
+ se_item_map = {}
+ for item in se_items:
+ se_item_map.setdefault(item.project_name, item.amount)
+
+ return se_item_map
+
+def get_delivered_items_cost():
+ dn_items = webnotes.conn.sql("""select dn.project_name, sum(dn_item.amount) as amount
+ from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
+ where dn.name = dn_item.parent and dn.docstatus = 1 and ifnull(dn.project_name, '') != ''
+ group by dn.project_name""", as_dict=1)
+
+ si_items = webnotes.conn.sql("""select si.project_name, sum(si_item.amount) as amount
+ from `tabSales Invoice` si, `tabSales Invoice Item` si_item
+ where si.name = si_item.parent and si.docstatus = 1 and ifnull(si.update_stock, 0) = 1
+ and ifnull(si.is_pos, 0) = 1 and ifnull(si.project_name, '') != ''
+ group by si.project_name""", as_dict=1)
+
+
+ dn_item_map = {}
+ for item in dn_items:
+ dn_item_map.setdefault(item.project_name, item.amount)
+
+ for item in si_items:
+ dn_item_map.setdefault(item.project_name, item.amount)
+
+ return dn_item_map
\ No newline at end of file
diff --git a/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.txt b/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.txt
new file mode 100644
index 0000000..89f5085
--- /dev/null
+++ b/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.txt
@@ -0,0 +1,21 @@
+[
+ {
+ "creation": "2013-06-03 17:37:41",
+ "docstatus": 0,
+ "modified": "2013-06-03 17:37:41",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "name": "__common__",
+ "ref_doctype": "Project",
+ "report_name": "Project wise Stock Tracking ",
+ "report_type": "Report Builder"
+ },
+ {
+ "doctype": "Report",
+ "name": "Project wise Stock Tracking"
+ }
+]
\ No newline at end of file
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index 57fc351..d2f25f0 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -505,17 +505,13 @@
if self.doc.use_multi_level_bom:
# get all raw materials with sub assembly childs
- fl_bom_sa_child_item = sql("""select
- item_code,ifnull(sum(qty_consumed_per_unit),0)*%s as qty,
- description,stock_uom
- from ( select distinct fb.name, fb.description, fb.item_code,
- fb.qty_consumed_per_unit, fb.stock_uom
- from `tabBOM Explosion Item` fb,`tabItem` it
- where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
- and ifnull(it.is_sub_contracted_item, 'No') = 'No' and fb.docstatus<2
- and fb.parent=%s
- ) a
- group by item_code, stock_uom""" , (qty, self.doc.bom_no), as_dict=1)
+ fl_bom_sa_child_item = sql("""select fb.item_code,
+ ifnull(sum(fb.qty_consumed_per_unit),0)*%s as qty, fb.description, 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 group by item_code, stock_uom""",
+ (qty, self.doc.bom_no), as_dict=1)
if fl_bom_sa_child_item:
_make_items_dict(fl_bom_sa_child_item)
@@ -523,10 +519,10 @@
# Get all raw materials considering multi level BOM,
# if multi level bom consider childs of Sub-Assembly items
fl_bom_sa_items = sql("""select item_code,
- ifnull(sum(qty_consumed_per_unit), 0) * '%s' as qty,
+ ifnull(sum(qty_consumed_per_unit), 0) *%s as qty,
description, stock_uom from `tabBOM Item`
- where parent = '%s' and docstatus < 2
- group by item_code""" % (qty, self.doc.bom_no), as_dict=1)
+ where parent = %s and docstatus < 2
+ group by item_code""", (qty, self.doc.bom_no), as_dict=1)
if fl_bom_sa_items:
_make_items_dict(fl_bom_sa_items)