From 35e037651c93fd87b178541efeda111bee527a1e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 11:58:57 +0530 Subject: [PATCH 1/7] fixes in packing slip --- stock/doctype/packing_slip/packing_slip.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/stock/doctype/packing_slip/packing_slip.js b/stock/doctype/packing_slip/packing_slip.js index a332ca8345..706c6f5141 100644 --- a/stock/doctype/packing_slip/packing_slip.js +++ b/stock/doctype/packing_slip/packing_slip.js @@ -28,18 +28,10 @@ cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query = func // Fetch item details -cur_frm.cscript.item_code = function(doc, cdt, cdn) { - if(locals[cdt][cdn].item_code) { - $c_obj(make_doclist(cdt, cdn), 'get_item_details', doc.delivery_note, function(r, rt) { - if(r.exc) { - msgprint(r.exc); - } else { - refresh_field('item_details'); - } - }); - } -} - +cur_frm.add_fetch("item_code", "item_name", "item_name"); +cur_frm.add_fetch("item_code", "stock_uom", "stock_uom"); +cur_frm.add_fetch("item_code", "net_weight", "net_weight"); +cur_frm.add_fetch("item_code", "weight_uom", "weight_uom"); cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { if(doc.delivery_note && doc.__islocal) { From c3afb256b450cbceab5b427297a80774ac4d3b52 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:01:24 +0530 Subject: [PATCH 2/7] aii: stock entry --- controllers/selling_controller.py | 29 +------ controllers/stock_controller.py | 71 +++++++++++++++++ stock/doctype/stock_entry/stock_entry.js | 9 ++- stock/doctype/stock_entry/stock_entry.py | 42 +++------- stock/doctype/stock_entry/stock_entry.txt | 79 +++++++++++++++---- stock/doctype/stock_entry/test_stock_entry.py | 3 + stock/stock_ledger.py | 2 +- stock/utils.py | 20 ++--- 8 files changed, 174 insertions(+), 81 deletions(-) create mode 100644 controllers/stock_controller.py diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 40606c3198..f9498cbac9 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -19,9 +19,9 @@ import webnotes from webnotes.utils import cint from setup.utils import get_company_currency -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class SellingController(AccountsController): +class SellingController(StockController): def validate(self): self.set_total_in_words() @@ -37,27 +37,4 @@ class SellingController(AccountsController): self.doc.grand_total or self.doc.rounded_total, company_currency) if self.meta.get_field("in_words_export"): self.doc.in_words_export = money_in_words(disable_rounded_total and - self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) - - def get_stock_ledger_entries(self): - item_list, warehouse_list = self.get_distinct_item_warehouse() - if item_list and warehouse_list: - return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, - voucher_detail_no, posting_date, posting_time, stock_value, - warehouse, actual_qty as qty from `tabStock Ledger Entry` - where ifnull(`is_cancelled`, "No") = "No" and company = %s - and item_code in (%s) and warehouse in (%s) - order by item_code desc, warehouse desc, posting_date desc, - posting_time desc, name desc""" % - ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), - tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) - - def get_distinct_item_warehouse(self): - item_list = [] - warehouse_list = [] - for item in self.doclist.get({"parentfield": self.fname}) \ - + self.doclist.get({"parentfield": "packing_details"}): - item_list.append(item.item_code) - warehouse_list.append(item.warehouse) - - return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file + self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py new file mode 100644 index 0000000000..3a900aa8be --- /dev/null +++ b/controllers/stock_controller.py @@ -0,0 +1,71 @@ +# 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 . + +from __future__ import unicode_literals +import webnotes +from controllers.accounts_controller import AccountsController + +class StockController(AccountsController): + def make_gl_entries(self, against_stock_account, amount, cost_center=None): + stock_in_hand_account = self.get_stock_in_hand_account() + + if amount: + gl_entries = [ + # stock in hand account + self.get_gl_dict({ + "account": stock_in_hand_account, + "against": against_stock_account, + "debit": amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock", + }, self.doc.docstatus == 2), + + # account against stock in hand + self.get_gl_dict({ + "account": against_stock_account, + "against": stock_in_hand_account, + "credit": amount, + "cost_center": cost_center or None, + "remarks": self.doc.remarks or "Accounting Entry for Stock", + }, self.doc.docstatus == 2), + ] + from accounts.general_ledger import make_gl_entries + make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + + + def get_stock_ledger_entries(self, item_list=None, warehouse_list=None): + if not (item_list and warehouse_list): + item_list, warehouse_list = self.get_distinct_item_warehouse() + + if item_list and warehouse_list: + return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, + voucher_detail_no, posting_date, posting_time, stock_value, + warehouse, actual_qty as qty from `tabStock Ledger Entry` + where ifnull(`is_cancelled`, "No") = "No" and company = %s + and item_code in (%s) and warehouse in (%s) + order by item_code desc, warehouse desc, posting_date desc, + posting_time desc, name desc""" % + ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), + tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) + + def get_distinct_item_warehouse(self): + item_list = [] + warehouse_list = [] + for item in self.doclist.get({"parentfield": self.fname}) \ + + self.doclist.get({"parentfield": "packing_details"}): + item_list.append(item.item_code) + warehouse_list.append(item.warehouse) + + return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index ba1f64802a..0a75914a62 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -234,4 +234,11 @@ cur_frm.cscript.validate_items = function(doc) { cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query; -cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; \ No newline at end of file +cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; + +cur_frm.fields_dict["expense_adjustment_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { "company": doc.company } + } +} \ 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 cd20266d6b..17e265591c 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -26,12 +26,11 @@ from stock.utils import get_incoming_rate from stock.stock_ledger import get_previous_sle import json - sql = webnotes.conn.sql -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class DocType(AccountsController): +class DocType(StockController): def __init__(self, doc, doclist=[]): self.doc = doc self.doclist = doclist @@ -168,41 +167,24 @@ class DocType(AccountsController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_in_hand_account = self.get_stock_in_hand_account() - total_valuation_amount = self.get_total_valuation_amount() - - if total_valuation_amount: - gl_entries = [ - # debit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": "Stock Adjustment - %s" % abbr, - "debit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # debit stock received but not billed account - self.get_gl_dict({ - "account": "Stock Adjustment - %s" % abbr, - "against": stock_in_hand_account, - "credit": total_valuation_amount, - "cost_center": "Auto Inventory Accounting - %s" % abbr, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + if not self.doc.expense_adjustment_account: + webnotes.msgprint(_("Please enter Expense/Adjustment Account"), raise_exception=1) + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) + total_valuation_amount = self.get_total_valuation_amount() + + super(DocType, self).make_gl_entries(self.doc.expense_adjustment_account, + total_valuation_amount, cost_center) + def get_total_valuation_amount(self): total_valuation_amount = 0 for item in self.doclist.get({"parentfield": "mtn_details"}): if item.t_warehouse and not item.s_warehouse: total_valuation_amount += flt(item.incoming_rate) * flt(item.transfer_qty) - + if item.s_warehouse and not item.t_warehouse: total_valuation_amount -= flt(item.incoming_rate) * flt(item.transfer_qty) - + return total_valuation_amount def get_stock_and_rate(self): diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt index 2554455764..013265244a 100644 --- a/stock/doctype/stock_entry/stock_entry.txt +++ b/stock/doctype/stock_entry/stock_entry.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-23 19:57:20", + "creation": "2013-03-07 18:50:32", "docstatus": 0, - "modified": "2013-01-28 17:59:20", + "modified": "2013-03-14 12:25:00", "modified_by": "Administrator", "owner": "Administrator" }, @@ -60,6 +60,7 @@ "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -76,6 +77,7 @@ "oldfieldtype": "Select", "options": "\nSTE", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -95,6 +97,7 @@ "oldfieldtype": "Select", "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nManufacture/Repack\nSubcontract\nSales Return\nPurchase Return", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -105,6 +108,7 @@ "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -122,6 +126,7 @@ "oldfieldname": "posting_date", "oldfieldtype": "Date", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 1 @@ -138,16 +143,26 @@ "oldfieldname": "posting_time", "oldfieldtype": "Time", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 }, + { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "expense_adjustment_account", + "fieldtype": "Link", + "label": "Expense/Adjustment Account", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "items_section", "fieldtype": "Section Break", "label": "Items", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "read_only": 0 }, { "allow_on_submit": 0, @@ -163,6 +178,7 @@ "oldfieldtype": "Link", "options": "Warehouse", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -170,7 +186,8 @@ { "doctype": "DocField", "fieldname": "cb0", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "allow_on_submit": 0, @@ -186,6 +203,7 @@ "oldfieldtype": "Link", "options": "Warehouse", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -194,7 +212,8 @@ "doctype": "DocField", "fieldname": "sb0", "fieldtype": "Section Break", - "options": "Simple" + "options": "Simple", + "read_only": 0 }, { "allow_on_submit": 0, @@ -209,6 +228,7 @@ "oldfieldtype": "Table", "options": "Stock Entry Detail", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -221,13 +241,15 @@ "label": "Get Stock and Rate", "oldfieldtype": "Button", "options": "get_stock_and_rate", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", "fieldname": "sb1", "fieldtype": "Section Break", - "label": "Reference" + "label": "Reference", + "read_only": 0 }, { "allow_on_submit": 0, @@ -243,6 +265,7 @@ "oldfieldtype": "Link", "options": "Production Order", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -253,7 +276,8 @@ "fieldname": "bom_no", "fieldtype": "Link", "label": "BOM No", - "options": "BOM" + "options": "BOM", + "read_only": 0 }, { "allow_on_submit": 0, @@ -269,6 +293,7 @@ "oldfieldname": "fg_completed_qty", "oldfieldtype": "Currency", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -287,6 +312,7 @@ "oldfieldtype": "Link", "options": "Delivery Note", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -305,6 +331,7 @@ "oldfieldtype": "Link", "options": "Purchase Receipt", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -312,7 +339,8 @@ { "doctype": "DocField", "fieldname": "cb1", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "default": "1", @@ -321,7 +349,8 @@ "doctype": "DocField", "fieldname": "use_multi_level_bom", "fieldtype": "Check", - "label": "Use Multi-Level BOM" + "label": "Use Multi-Level BOM", + "read_only": 0 }, { "allow_on_submit": 0, @@ -335,6 +364,7 @@ "no_copy": 0, "oldfieldtype": "Button", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -348,14 +378,16 @@ "label": "Sales Invoice No", "no_copy": 1, "options": "Sales Invoice", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")", "doctype": "DocField", "fieldname": "contact_section", "fieldtype": "Section Break", - "label": "Contact Info" + "label": "Contact Info", + "read_only": 0 }, { "allow_on_submit": 0, @@ -371,6 +403,7 @@ "oldfieldtype": "Link", "options": "Supplier", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -406,6 +439,7 @@ "oldfieldname": "supplier_address", "oldfieldtype": "Small Text", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -424,6 +458,7 @@ "oldfieldtype": "Link", "options": "Customer", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -459,6 +494,7 @@ "oldfieldname": "customer_address", "oldfieldtype": "Small Text", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -468,13 +504,15 @@ "fieldname": "more_info", "fieldtype": "Section Break", "label": "More Info", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "col4", "fieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -485,7 +523,8 @@ "label": "Project Name", "oldfieldname": "project_name", "oldfieldtype": "Link", - "options": "Project" + "options": "Project", + "read_only": 0 }, { "allow_on_submit": 0, @@ -500,6 +539,7 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -517,6 +557,7 @@ "oldfieldtype": "Link", "options": "Company", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -526,6 +567,7 @@ "fieldname": "col5", "fieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -558,6 +600,7 @@ "oldfieldname": "remarks", "oldfieldtype": "Text", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -569,5 +612,13 @@ { "doctype": "DocPerm", "role": "Manufacturing User" + }, + { + "doctype": "DocPerm", + "role": "Manufacturing Manager" + }, + { + "doctype": "DocPerm", + "role": "Material Manager" } ] \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index a4103c37bb..f193826402 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -168,6 +168,7 @@ test_records = [ "posting_time": "17:14:24", "purpose": "Material Receipt", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, @@ -190,6 +191,7 @@ test_records = [ "posting_time": "17:15", "purpose": "Material Issue", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, @@ -212,6 +214,7 @@ test_records = [ "posting_time": "17:14:24", "purpose": "Material Transfer", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index 883ced7f71..d00b243e81 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -71,7 +71,7 @@ def update_entries_after(args, verbose=1): (qty_after_transaction * valuation_rate) or 0 else: stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) - + # print sle.posting_date, sle.actual_qty, sle.incoming_rate, stock_queue, stock_value # update current sle webnotes.conn.sql("""update `tabStock Ledger Entry` set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, diff --git a/stock/utils.py b/stock/utils.py index bf5e2f9dcd..b4d07701ff 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -165,8 +165,8 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): return wlist def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no, - stock_ledger_entries, item_sales_bom): - if item_sales_bom.get(item_code): + stock_ledger_entries, item_sales_bom=None): + if item_sales_bom and item_sales_bom.get(item_code): # sales bom item buying_amount = 0.0 for bom_item in item_sales_bom[item_code]: @@ -182,13 +182,15 @@ def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse, stock_ledger_entries): for i, sle in enumerate(stock_ledger_entries): if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \ - len(stock_ledger_entries) > i+1: - if (sle.voucher_detail_no == item_row) or \ - (sle.item_code == item_code and sle.warehouse == warehouse and \ - abs(flt(sle.qty)) == qty): - buying_amount = flt(stock_ledger_entries[i+1].stock_value) - \ - flt(sle.stock_value) - return buying_amount + (sle.voucher_detail_no == item_row or (sle.voucher_type != "Stock Reconciliation" + and sle.item_code == item_code and sle.warehouse == warehouse and flt(sle.qty) == qty)): + # print "previous_sle", stock_ledger_entries[i+1] + # print "current sle", sle + previous_stock_value = len(stock_ledger_entries) > i+1 and \ + flt(stock_ledger_entries[i+1].stock_value) or 0.0 + + buying_amount = previous_stock_value - flt(sle.stock_value) + return buying_amount return 0.0 def get_sales_bom(): From 89a94d8135f4c22c9b22522ec1f00c9a9c064207 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:01:46 +0530 Subject: [PATCH 3/7] aii: stock reconciliation with test case --- accounts/doctype/account/account.py | 2 +- accounts/doctype/fiscal_year/fiscal_year.txt | 23 +- .../purchase_invoice/purchase_invoice.js | 7 +- .../doctype/sales_invoice/sales_invoice.js | 21 +- .../doctype/sales_invoice/sales_invoice.py | 3 +- .../sales_invoice_item/sales_invoice_item.txt | 8 +- accounts/report/gross_profit/gross_profit.py | 6 +- controllers/accounts_controller.py | 2 +- controllers/buying_controller.py | 4 +- setup/doctype/company/company.py | 48 ++-- setup/doctype/company/company.txt | 59 ++++- stock/doctype/delivery_note/delivery_note.py | 33 +-- .../purchase_receipt/purchase_receipt.py | 29 +-- .../stock_reconciliation.js | 17 +- .../stock_reconciliation.py | 79 ++++-- .../stock_reconciliation.txt | 34 ++- .../test_stock_reconciliation.py | 230 ++++++++++++------ 17 files changed, 383 insertions(+), 222 deletions(-) diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py index 08bf80fdce..3cd131fc29 100644 --- a/accounts/doctype/account/account.py +++ b/accounts/doctype/account/account.py @@ -207,4 +207,4 @@ def get_parent_account(doctype, txt, searchfield, start, page_len, filters): where group_or_ledger = 'Group' and docstatus != 2 and company = %s and %s like %s order by name limit %s, %s""" % ("%s", searchfield, "%s", "%s", "%s"), - (filters["company"], "%%%s%%" % txt, start, page_len), as_list=1) + (filters["company"], "%%%s%%" % txt, start, page_len), as_list=1) \ No newline at end of file diff --git a/accounts/doctype/fiscal_year/fiscal_year.txt b/accounts/doctype/fiscal_year/fiscal_year.txt index 18f20dd4f1..935b76f16f 100644 --- a/accounts/doctype/fiscal_year/fiscal_year.txt +++ b/accounts/doctype/fiscal_year/fiscal_year.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-10 16:34:06", + "creation": "2013-01-22 16:50:25", "docstatus": 0, - "modified": "2013-01-22 14:46:59", + "modified": "2013-03-13 12:29:40", "modified_by": "Administrator", "owner": "Administrator" }, @@ -23,7 +23,6 @@ "permlevel": 0 }, { - "amend": 0, "cancel": 1, "create": 1, "doctype": "DocPerm", @@ -42,22 +41,6 @@ "doctype": "DocType", "name": "Fiscal Year" }, - { - "doctype": "DocField", - "fieldname": "year_details", - "fieldtype": "Section Break", - "label": "Fiscal Year Details", - "oldfieldtype": "Section Break" - }, - { - "doctype": "DocField", - "fieldname": "trash_reason", - "fieldtype": "Small Text", - "label": "Trash Reason", - "oldfieldname": "trash_reason", - "oldfieldtype": "Small Text", - "read_only": 1 - }, { "description": "For e.g. 2012, 2012-13", "doctype": "DocField", @@ -73,6 +56,7 @@ "fieldname": "year_start_date", "fieldtype": "Date", "label": "Year Start Date", + "no_copy": 1, "oldfieldname": "year_start_date", "oldfieldtype": "Date", "reqd": 1 @@ -84,6 +68,7 @@ "fieldname": "is_fiscal_year_closed", "fieldtype": "Select", "label": "Year Closed", + "no_copy": 1, "oldfieldname": "is_fiscal_year_closed", "oldfieldtype": "Select", "options": "\nNo\nYes", diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js index f4a2e68e5f..4a1cbbac17 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -238,8 +238,11 @@ cur_frm.cscript.expense_head = function(doc, cdt, cdn){ refresh_field('entries'); } -cur_frm.fields_dict['entries'].grid.get_field("cost_center").get_query = function(doc) { - return 'SELECT `tabCost Center`.`name` FROM `tabCost Center` WHERE `tabCost Center`.`company_name` = "' +doc.company+'" AND `tabCost Center`.%(key)s LIKE "%s" AND `tabCost Center`.`group_or_ledger` = "Ledger" AND `tabCost Center`.docstatus != 2 ORDER BY `tabCost Center`.`name` ASC LIMIT 50'; +cur_frm.fields_dict["entries"].grid.get_field("cost_center").get_query = function(doc) { + return { + query: "accounts.utils.get_cost_center_list", + filters: { company_name: doc.company} + } } cur_frm.cscript.cost_center = function(doc, cdt, cdn){ diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index a24e256ec9..5cc09a0c10 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -271,8 +271,6 @@ cur_frm.cscript.is_opening = function(doc, dt, dn) { if (doc.is_opening == 'Yes') unhide_field('aging_date'); } -/* **************************** TRIGGERS ********************************** */ - // Get Items based on SO or DN Selected cur_frm.cscript.get_items = function(doc, dt, dn) { var callback = function(r,rt) { @@ -371,6 +369,18 @@ cur_frm.set_query("income_account", "entries", function(doc) { return 'SELECT tabAccount.name FROM tabAccount WHERE (tabAccount.debit_or_credit="Credit" OR tabAccount.account_type = "Income Account") AND tabAccount.group_or_ledger="Ledger" AND tabAccount.docstatus!=2 AND tabAccount.company="'+doc.company+'" AND tabAccount.%(key)s LIKE "%s"'; }) +// expense account +cur_frm.fields_dict['entries'].grid.get_field('expense_account').get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.company + } + } +} + // warehouse in detail table //---------------------------- cur_frm.fields_dict['entries'].grid.get_field('warehouse').get_query= function(doc, cdt, cdn) { @@ -380,8 +390,11 @@ cur_frm.fields_dict['entries'].grid.get_field('warehouse').get_query= function(d // Cost Center in Details Table // ----------------------------- -cur_frm.fields_dict.entries.grid.get_field("cost_center").get_query = function(doc) { - return 'SELECT `tabCost Center`.`name` FROM `tabCost Center` WHERE `tabCost Center`.`company_name` = "' +doc.company+'" AND `tabCost Center`.%(key)s LIKE "%s" AND `tabCost Center`.`group_or_ledger` = "Ledger" AND `tabCost Center`.`docstatus`!= 2 ORDER BY `tabCost Center`.`name` ASC LIMIT 50'; +cur_frm.fields_dict["entries"].grid.get_field("cost_center").get_query = function(doc) { + return { + query: "accounts.utils.get_cost_center_list", + filters: { company_name: doc.company} + } } // Sales Order diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index de3ee95897..b6b1f0ba10 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -804,8 +804,9 @@ class DocType(SellingController): item_buying_amount = 0 if stock_ledger_entries: # is pos and update stock - item_buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + item_buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) + item.buying_amount = item_buying_amount > 0 and item_buying_amount or 0 elif item.delivery_note and item.dn_detail: # against delivery note dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail, diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt index ca078b53f4..6f6ad399c5 100644 --- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt +++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:42:55", "docstatus": 0, - "modified": "2013-03-11 14:58:50", + "modified": "2013-03-18 15:41:19", "modified_by": "Administrator", "owner": "Administrator" }, @@ -207,14 +207,16 @@ "width": "120px" }, { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", - "hidden": 1, + "hidden": 0, "in_filter": 1, "label": "Expense Account", "options": "Account", - "print_hide": 1 + "print_hide": 1, + "width": "120px" }, { "doctype": "DocField", diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index f1ae00e13f..2480e17679 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -24,8 +24,10 @@ def execute(filters=None): data = [] for row in delivery_note_items: selling_amount = flt(row.amount) - buying_amount = get_buying_amount(row.item_code, row.warehouse, - row.qty, "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) + buying_amount = get_buying_amount(row.item_code, row.warehouse, -1*row.qty, + "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) + buying_amount = buying_amount > 0 and buying_amount or 0 + if selling_amount: gross_profit = selling_amount - buying_amount gross_profit_percent = (gross_profit / selling_amount) * 100.0 diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 73d7608240..f328473329 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -18,6 +18,7 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint, _ from webnotes.utils import flt + from utilities.transaction_base import TransactionBase class AccountsController(TransactionBase): @@ -70,7 +71,6 @@ class AccountsController(TransactionBase): def get_stock_in_hand_account(self): stock_in_hand_account = webnotes.conn.get_value("Company", self.doc.company, "stock_in_hand_account") - if not stock_in_hand_account: msgprint(_("Missing") + ": " + _(webnotes.get_doctype("company").get_label("stock_in_hand_account") diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 2f3128c98c..03d2a92660 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -24,9 +24,9 @@ from buying.utils import get_item_details from setup.utils import get_company_currency from webnotes.model.utils import round_floats_in_doc -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class BuyingController(AccountsController): +class BuyingController(StockController): def validate(self): if self.meta.get_field("currency"): self.company_currency = get_company_currency(self.doc.company) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 9cf722fca4..405171760b 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -17,7 +17,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, set_default +from webnotes.utils import cstr from webnotes.model.doc import Document from webnotes.model.code import get_obj import webnotes.defaults @@ -49,6 +49,8 @@ class DocType: ['Earnest Money','Securities and Deposits','Ledger','No','','Debit',self.doc.name,''], ['Stock In Hand','Current Assets','Group','No','','Debit',self.doc.name,''], ['Stock','Stock In Hand','Ledger','No','','Debit',self.doc.name,''], + ['Stock Delivered But Not Billed', 'Stock In Hand', 'Ledger', + 'No', '', 'Debit', self.doc.name, ''], ['Tax Assets','Current Assets','Group','No','','Debit',self.doc.name,''], ['Stock Delivered But Not Billed','Current Assets','Ledger','No','','Debit',self.doc.name,''], ['Fixed Assets','Application of Funds (Assets)','Group','No','','Debit',self.doc.name,''], @@ -62,9 +64,9 @@ class DocType: ['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','No','','Debit',self.doc.name,''], ['Expenses','','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Direct Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], - ['Cost of Goods Sold','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], - ['Expenses Included In Valuation','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], - ['Stock Adjustment','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Stock Expenses','Direct Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], + ['Cost of Goods Sold','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Stock Adjustment','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], ['Indirect Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Advertising and Publicity','Indirect Expenses','Ledger','Yes','Chargeable','Debit',self.doc.name,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], @@ -101,6 +103,9 @@ class DocType: ['Shareholders Funds','Capital Account','Group','No','','Credit',self.doc.name,''], ['Current Liabilities','Source of Funds (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Accounts Payable','Current Liabilities','Group','No','','Credit',self.doc.name,''], + ['Stock Liabilities','Current Liabilities','Group','No','','Credit',self.doc.name,''], + ['Stock Received But Not Billed', 'Stock Liabilities', 'Ledger', + 'No', '', 'Credit', self.doc.name, ''], ['Duties and Taxes','Current Liabilities','Group','No','','Credit',self.doc.name,''], ['Loans (Liabilities)','Current Liabilities','Group','No','','Credit',self.doc.name,''], ['Secured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], @@ -186,14 +191,30 @@ class DocType: self.doc.letter_head = header - # Set default AR and AP group - # --------------------------------------------------- - def set_default_groups(self): - if not self.doc.receivables_group: - webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - '+self.doc.abbr) - if not self.doc.payables_group: - webnotes.conn.set(self.doc, 'payables_group', 'Accounts Payable - '+self.doc.abbr) + def set_default_accounts(self): + if not self.doc.receivables_group and webnotes.conn.exists('Account', + 'Accounts Receivable - ' + self.doc.abbr): + webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - ' + + self.doc.abbr) + + if not self.doc.payables_group and webnotes.conn.exists('Account', + 'Accounts Payable - ' + self.doc.abbr): + webnotes.conn.set(self.doc, 'payables_group', 'Accounts Payable - ' + self.doc.abbr) + if not self.doc.stock_delivered_but_not_billed and webnotes.conn.exists("Account", + "Stock Delivered But Not Billed - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_delivered_but_not_billed", + "Stock Delivered But Not Billed - " + self.doc.abbr) + + if not self.doc.stock_received_but_not_billed and webnotes.conn.exists("Account", + "Stock Received But Not Billed - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_received_but_not_billed", + "Stock Received But Not Billed - " + self.doc.abbr) + + if not self.doc.stock_adjustment_account and webnotes.conn.exists("Account", + "Stock Adjustment - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_adjustment_account", "Stock Adjustment - " + + self.doc.abbr) # Create default cost center # --------------------------------------------------- @@ -228,7 +249,7 @@ class DocType: self.doc.name) if not ac: self.create_default_accounts() - self.set_default_groups() + self.set_default_accounts() cc = sql("select name from `tabCost Center` where cost_center_name = 'Root' and company_name = '%s'"%(self.doc.name)) if not cc: self.create_default_cost_center() @@ -258,9 +279,6 @@ class DocType: #update value as blank for tabSingles Global Defaults sql("update `tabSingles` set value = '' where doctype='Global Defaults' and field = 'default_company' and value = %s", self.doc.name) - - # on rename - # --------- def on_rename(self,newdn,olddn): sql("update `tabCompany` set company_name = '%s' where name = '%s'" %(newdn,olddn)) sql("update `tabSingles` set value = %s where doctype='Global Defaults' and field = 'default_company' and value = %s", (newdn, olddn)) diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt index d97cfc34af..d8c649ff28 100644 --- a/setup/doctype/company/company.txt +++ b/setup/doctype/company/company.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:27:54", + "creation": "2013-02-27 09:38:05", "docstatus": 0, - "modified": "2013-02-26 10:57:39", + "modified": "2013-03-18 16:34:04", "modified_by": "Administrator", "owner": "Administrator" }, @@ -124,17 +124,6 @@ "oldfieldtype": "Link", "options": "Account" }, - { - "depends_on": "eval:!doc.__islocal", - "description": "This account will be used to maintain value of available stock", - "doctype": "DocField", - "fieldname": "stock_in_hand_account", - "fieldtype": "Link", - "label": "Stock In Hand Account", - "no_copy": 1, - "options": "Account", - "read_only": 0 - }, { "doctype": "DocField", "fieldname": "column_break0", @@ -181,6 +170,50 @@ "oldfieldtype": "Select", "options": "\nWarn\nIgnore\nStop" }, + { + "depends_on": "eval:!doc.__islocal && sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "auto_inventory_accounting_settings", + "fieldtype": "Section Break", + "label": "Auto Inventory Accounting Settings" + }, + { + "description": "This account will be used to maintain value of available stock", + "doctype": "DocField", + "fieldname": "stock_in_hand_account", + "fieldtype": "Link", + "label": "Stock In Hand Account", + "no_copy": 1, + "options": "Account", + "read_only": 0 + }, + { + "doctype": "DocField", + "fieldname": "stock_adjustment_account", + "fieldtype": "Link", + "label": "Stock Adjustment Account", + "options": "Account" + }, + { + "doctype": "DocField", + "fieldname": "col_break23", + "fieldtype": "Column Break", + "width": "50%" + }, + { + "doctype": "DocField", + "fieldname": "stock_delivered_but_not_billed", + "fieldtype": "Link", + "label": "Stock Delivered But Not Billed", + "options": "Account" + }, + { + "doctype": "DocField", + "fieldname": "stock_received_but_not_billed", + "fieldtype": "Link", + "label": "Stock Received But Not Billed", + "options": "Account" + }, { "description": "For reference only.", "doctype": "DocField", diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 229ec40a54..aef79390c2 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -24,7 +24,6 @@ from webnotes import msgprint sql = webnotes.conn.sql - from controllers.selling_controller import SellingController class DocType(SellingController): @@ -401,9 +400,10 @@ class DocType(SellingController): if stock_ledger_entries: for item in self.doclist.get({"parentfield": "delivery_note_details"}): - item.buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) + item.buying_amount = buying_amount > 0 and buying_amount or 0 webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", item.buying_amount) @@ -420,32 +420,11 @@ class DocType(SellingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_delivered_account = "Stock Delivered But Not Billed - %s" % (abbr,) - stock_in_hand_account = self.get_stock_in_hand_account() - + against_stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) total_buying_amount = self.get_total_buying_amount() - if total_buying_amount: - gl_entries = [ - # credit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": stock_delivered_account, - "credit": total_buying_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # debit stock received but not billed account - self.get_gl_dict({ - "account": stock_delivered_account, - "against": stock_in_hand_account, - "debit": total_buying_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) - + + super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) + def get_total_buying_amount(self): total_buying_amount = sum([item.buying_amount for item in self.doclist.get({"parentfield": "delivery_note_details"})]) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index cce1493141..e26c0a6d1e 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -20,8 +20,7 @@ import webnotes from webnotes.utils import cstr, flt, cint from webnotes.model.bean import getlist from webnotes.model.code import get_obj -from webnotes.model.doc import Document -from webnotes import msgprint, _ +from webnotes import msgprint sql = webnotes.conn.sql @@ -319,32 +318,10 @@ class DocType(BuyingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_received_account = "Stock Received But Not Billed - %s" % (abbr,) - stock_in_hand_account = self.get_stock_in_hand_account() - + against_stock_account = "Stock Received But Not Billed - %s" % (self.company_abbr,) total_valuation_amount = self.get_total_valuation_amount() - if total_valuation_amount: - gl_entries = [ - # debit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": stock_received_account, - "debit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # credit stock received but not billed account - self.get_gl_dict({ - "account": stock_received_account, - "against": stock_in_hand_account, - "credit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) def get_total_valuation_amount(self): total_valuation_amount = 0.0 diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.js b/stock/doctype/stock_reconciliation/stock_reconciliation.js index f1508ac766..fb4053ca9e 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.js +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.js @@ -18,6 +18,10 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ + setup: function() { + this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); + }, + refresh: function() { if(this.frm.doc.docstatus===0) { this.show_download_template(); @@ -122,4 +126,15 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ }, }); -cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); \ No newline at end of file +cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); + +cur_frm.fields_dict["expense_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.company + } + } +} \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index e0f7f09c58..c2f5a940c5 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -18,22 +18,26 @@ from __future__ import unicode_literals import webnotes import json from webnotes import msgprint, _ -from webnotes.utils import cstr, flt -from webnotes.model.controller import DocListController +from webnotes.utils import cstr, flt, cint from stock.stock_ledger import update_entries_after +from controllers.stock_controller import StockController -class DocType(DocListController): +class DocType(StockController): def setup(self): self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] + self.entries = [] def validate(self): self.validate_data() def on_submit(self): self.insert_stock_ledger_entries() + self.set_stock_value_difference() + self.make_gl_entries() def on_cancel(self): self.delete_stock_ledger_entries() + self.make_gl_entries() def validate_data(self): if not self.doc.reconciliation_json: @@ -134,6 +138,7 @@ class DocType(DocListController): data = json.loads(self.doc.reconciliation_json) for row_num, row in enumerate(data[data.index(self.head_row)+1:]): row = webnotes._dict(zip(row_template, row)) + row["row_num"] = row_num previous_sle = get_previous_sle({ "item_code": row.item_code, "warehouse": row.warehouse, @@ -162,8 +167,7 @@ class DocType(DocListController): def sle_for_moving_avg(self, row, previous_sle, change_in_qty, change_in_rate): """Insert Stock Ledger Entries for Moving Average valuation""" - def _get_incoming_rate(qty, valuation_rate, previous_qty, - previous_valuation_rate): + def _get_incoming_rate(qty, valuation_rate, previous_qty, previous_valuation_rate): if previous_valuation_rate == 0: return flt(valuation_rate) else: @@ -177,9 +181,9 @@ class DocType(DocListController): incoming_rate = _get_incoming_rate(flt(row.qty), flt(row.valuation_rate), flt(previous_sle.get("qty_after_transaction")), flt(previous_sle.get("valuation_rate"))) - - self.insert_entries({"actual_qty": change_in_qty, - "incoming_rate": incoming_rate}, row) + + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry" + self.insert_entries({"actual_qty": change_in_qty, "incoming_rate": incoming_rate}, row) elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) > 0: # if no change in qty, but change in rate @@ -190,9 +194,11 @@ class DocType(DocListController): flt(previous_sle.get("valuation_rate"))) # +1 entry + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment +1" self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row) # -1 entry + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment -1" self.insert_entries({"actual_qty": -1}, row) def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate): @@ -206,14 +212,16 @@ class DocType(DocListController): if previous_stock_queue != [[row.qty, row.valuation_rate]]: # make entry as per attachment if row.qty: + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry" self.insert_entries({"actual_qty": row.qty, "incoming_rate": flt(row.valuation_rate)}, row) # Make reverse entry if previous_stock_qty: + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Reverse Entry" self.insert_entries({"actual_qty": -1 * previous_stock_qty, - "incoming_rate": previous_stock_qty < 0 and \ - flt(row.valuation_rate) or 0}, row) + "incoming_rate": previous_stock_qty < 0 and + flt(row.valuation_rate) or 0}, row) if change_in_qty: @@ -221,8 +229,7 @@ class DocType(DocListController): # dont want change in valuation if previous_stock_qty > 0: # set valuation_rate as previous valuation_rate - row.valuation_rate = \ - previous_stock_value / flt(previous_stock_qty) + row.valuation_rate = previous_stock_value / flt(previous_stock_qty) _insert_entries() @@ -234,8 +241,8 @@ class DocType(DocListController): _insert_entries() def insert_entries(self, opts, row): - """Insert Stock Ledger Entries""" - args = { + """Insert Stock Ledger Entries""" + args = webnotes._dict({ "doctype": "Stock Ledger Entry", "item_code": row.item_code, "warehouse": row.warehouse, @@ -243,9 +250,10 @@ class DocType(DocListController): "posting_time": self.doc.posting_time, "voucher_type": self.doc.doctype, "voucher_no": self.doc.name, - "company": webnotes.conn.get_default("company"), + "company": self.doc.company, "is_cancelled": "No", - } + "voucher_detail_no": row.voucher_detail_no + }) args.update(opts) # create stock ledger entry sle_wrapper = webnotes.bean([args]) @@ -254,17 +262,18 @@ class DocType(DocListController): # update bin webnotes.get_obj('Warehouse', row.warehouse).update_bin(args) - - return sle_wrapper + + # append to entries + self.entries.append(args) def delete_stock_ledger_entries(self): """ Delete Stock Ledger Entries related to this Stock Reconciliation and repost future Stock Ledger Entries""" - + existing_entries = webnotes.conn.sql("""select item_code, warehouse - from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' + from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s""", self.doc.name, as_dict=1) - + # delete entries webnotes.conn.sql("""delete from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s""", self.doc.name) @@ -277,7 +286,33 @@ class DocType(DocListController): "posting_date": self.doc.posting_date, "posting_time": self.doc.posting_time }) - + + def set_stock_value_difference(self): + """stock_value_difference is the increment in the stock value""" + from stock.utils import get_buying_amount + + item_list = [d.item_code for d in self.entries] + warehouse_list = [d.warehouse for d in self.entries] + stock_ledger_entries = self.get_stock_ledger_entries(item_list, warehouse_list) + + self.doc.stock_value_difference = 0.0 + for d in self.entries: + self.doc.stock_value_difference -= get_buying_amount(d.item_code, d.warehouse, + d.actual_qty, self.doc.doctype, self.doc.name, d.voucher_detail_no, + stock_ledger_entries) + webnotes.conn.set(self.doc, "stock_value_difference", self.doc.stock_value_difference) + + def make_gl_entries(self): + if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): + return + + if not self.doc.expense_account: + msgprint(_("Please enter Expense Account"), raise_exception=1) + + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) + + super(DocType, self).make_gl_entries(self.doc.expense_account, + self.doc.stock_value_difference, cost_center) @webnotes.whitelist() def upload(): diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/stock/doctype/stock_reconciliation/stock_reconciliation.txt index 094e90384f..9137cae972 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.txt +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-19 10:23:35", + "creation": "2013-01-22 16:50:41", "docstatus": 0, - "modified": "2013-01-22 14:57:24", + "modified": "2013-03-18 12:48:42", "modified_by": "Administrator", "owner": "Administrator" }, @@ -30,6 +30,7 @@ "permlevel": 0 }, { + "amend": 1, "cancel": 1, "create": 1, "doctype": "DocPerm", @@ -40,6 +41,7 @@ "permlevel": 0, "read": 1, "report": 1, + "role": "Material Manager", "submit": 1, "write": 1 }, @@ -79,6 +81,22 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 + }, + { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "expense_account", + "fieldtype": "Link", + "label": "Expense Account", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "col1", @@ -119,12 +137,14 @@ "read_only": 1 }, { - "amend": 0, - "doctype": "DocPerm", - "role": "Material Manager" + "doctype": "DocField", + "fieldname": "stock_value_difference", + "fieldtype": "Currency", + "hidden": 1, + "label": "Stock Value Difference", + "print_hide": 1 }, { - "doctype": "DocPerm", - "role": "System Manager" + "doctype": "DocPerm" } ] \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 80579aed5b..cebc6ffc53 100644 --- a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -1,40 +1,15 @@ # 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 . - +# For license information, please see license.txt from __future__ import unicode_literals -import unittest -import webnotes -from webnotes.tests import insert_test_data +import webnotes, unittest from webnotes.utils import flt import json - -company = webnotes.conn.get_default("company") +from accounts.utils import get_fiscal_year class TestStockReconciliation(unittest.TestCase): - def setUp(self): - webnotes.conn.begin() - self.insert_test_data() - - def tearDown(self): - # print "Message Log:", "\n--\n".join(webnotes.message_log) - # print "Debug Log:", "\n--\n".join(webnotes.debug_log) - webnotes.conn.rollback() - def test_reco_for_fifo(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) # [[qty, valuation_rate, posting_date, # posting_time, expected_stock_value, bin_qty, bin_valuation]] input_data = [ @@ -53,28 +28,32 @@ class TestStockReconciliation(unittest.TestCase): ] for d in input_data: + self.cleanup_data() self.insert_existing_sle("FIFO") - - self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + # check stock value res = webnotes.conn.sql("""select stock_value from `tabStock Ledger Entry` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse' + where item_code = '_Test Item' and warehouse = '_Test Warehouse' and posting_date = %s and posting_time = %s order by name desc limit 1""", (d[2], d[3])) - self.assertEqual(res and flt(res[0][0]) or 0, d[4]) + # check bin qty and stock value bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse'""") + where item_code = '_Test Item' and warehouse = '_Test Warehouse'""") self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1])] or [], [d[5], d[6]]) + # no gl entries + gl_entries = webnotes.conn.sql("""select name from `tabGL Entry` + where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", + stock_reco.doc.name) + self.assertFalse(gl_entries) - self.tearDown() - self.setUp() - def test_reco_for_moving_average(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) # [[qty, valuation_rate, posting_date, # posting_time, expected_stock_value, bin_qty, bin_valuation]] input_data = [ @@ -94,95 +73,194 @@ class TestStockReconciliation(unittest.TestCase): ] for d in input_data: + self.cleanup_data() self.insert_existing_sle("Moving Average") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) - self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) - + # check stock value in sle res = webnotes.conn.sql("""select stock_value from `tabStock Ledger Entry` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse' + where item_code = '_Test Item' and warehouse = '_Test Warehouse' and posting_date = %s and posting_time = %s order by name desc limit 1""", (d[2], d[3])) self.assertEqual(res and flt(res[0][0], 4) or 0, d[4]) + # bin qty and stock value bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse'""") + where item_code = '_Test Item' and warehouse = '_Test Warehouse'""") self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1], 4)] or [], [flt(d[5]), flt(d[6])]) - - self.tearDown() - self.setUp() + + # no gl entries + gl_entries = webnotes.conn.sql("""select name from `tabGL Entry` + where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", + stock_reco.doc.name) + self.assertFalse(gl_entries) + def test_reco_fifo_gl_entries(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + # [[qty, valuation_rate, posting_date, + # posting_time, stock_in_hand_debit]] + input_data = [ + [50, 1000, "2012-12-26", "12:00", 38000], + [5, 1000, "2012-12-26", "12:00", -7000], + [15, 1000, "2012-12-26", "12:00", 3000], + [25, 900, "2012-12-26", "12:00", 10500], + [20, 500, "2012-12-26", "12:00", -2000], + ["", 1000, "2012-12-26", "12:05", 3000], + [20, "", "2012-12-26", "12:05", 4000], + [10, 2000, "2012-12-26", "12:10", 8000], + [0, "", "2012-12-26", "12:10", -12000], + [50, 1000, "2013-01-01", "12:00", 50000], + [5, 1000, "2013-01-01", "12:00", 5000], + [1, 1000, "2012-12-01", "00:00", 1000], + + ] + + for d in input_data: + self.cleanup_data() + self.insert_existing_sle("FIFO") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + + # check gl_entries + self.check_gl_entries(stock_reco.doc.name, d[4]) + + # cancel + stock_reco.cancel() + self.check_gl_entries(stock_reco.doc.name, -d[4], True) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_reco_moving_average_gl_entries(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + # [[qty, valuation_rate, posting_date, + # posting_time, stock_in_hand_debit]] + input_data = [ + [50, 1000, "2012-12-26", "12:00", 36500], + [5, 1000, "2012-12-26", "12:00", -8500], + [15, 1000, "2012-12-26", "12:00", 1500], + [25, 900, "2012-12-26", "12:00", 9000], + [20, 500, "2012-12-26", "12:00", -3500], + ["", 1000, "2012-12-26", "12:05", 1500], + [20, "", "2012-12-26", "12:05", 4500], + [10, 2000, "2012-12-26", "12:10", 6500], + [0, "", "2012-12-26", "12:10", -13500], + [50, 1000, "2013-01-01", "12:00", 50000], + [5, 1000, "2013-01-01", "12:00", 5000], + [1, 1000, "2012-12-01", "00:00", 1000], + + ] + + for d in input_data: + self.cleanup_data() + self.insert_existing_sle("Moving Average") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + + # check gl_entries + self.check_gl_entries(stock_reco.doc.name, d[4]) + + # cancel + stock_reco.cancel() + self.check_gl_entries(stock_reco.doc.name, -d[4], True) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + + def cleanup_data(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("delete from tabBin") + def submit_stock_reconciliation(self, qty, rate, posting_date, posting_time): - return webnotes.bean([{ + stock_reco = webnotes.bean([{ "doctype": "Stock Reconciliation", - "name": "RECO-001", - "__islocal": 1, "posting_date": posting_date, "posting_time": posting_time, + "fiscal_year": get_fiscal_year(posting_date)[0], + "company": "_Test Company", + "expense_account": "Stock Adjustment - _TC", "reconciliation_json": json.dumps([ ["Item Code", "Warehouse", "Quantity", "Valuation Rate"], - ["Android Jack D", "Default Warehouse", qty, rate] + ["_Test Item", "_Test Warehouse", qty, rate] ]), - }]).submit() + }]) + stock_reco.insert() + stock_reco.submit() + return stock_reco - def insert_test_data(self): - # 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"}) - - # 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") + def check_gl_entries(self, voucher_no, stock_value_diff, cancel=None): + stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company", + "stock_in_hand_account") + debit_amount = stock_value_diff > 0 and stock_value_diff or 0.0 + credit_amount = stock_value_diff < 0 and abs(stock_value_diff) or 0.0 + + expected_gl_entries = sorted([ + [stock_in_hand_account, debit_amount, credit_amount], + ["Stock Adjustment - _TC", credit_amount, debit_amount] + ]) + if cancel: + expected_gl_entries = sorted([ + [stock_in_hand_account, debit_amount, credit_amount], + ["Stock Adjustment - _TC", credit_amount, debit_amount], + [stock_in_hand_account, credit_amount, debit_amount], + ["Stock Adjustment - _TC", debit_amount, credit_amount] + ]) + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s + order by account asc, debit asc""", voucher_no, as_dict=1) + self.assertTrue(gl_entries) + + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_gl_entries[i][0], gle.account) + self.assertEquals(expected_gl_entries[i][1], gle.debit) + self.assertEquals(expected_gl_entries[i][2], gle.credit) def insert_existing_sle(self, valuation_method): - webnotes.conn.set_value("Item", "Android Jack D", "valuation_method", valuation_method) + webnotes.conn.set_value("Item", "_Test Item", "valuation_method", valuation_method) webnotes.conn.set_default("allow_negative_stock", 1) existing_ledgers = [ { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-12", "posting_time": "01:00", - "actual_qty": 20, "incoming_rate": 1000, "company": company + "actual_qty": 20, "incoming_rate": 1000, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-15", "posting_time": "02:00", - "actual_qty": 10, "incoming_rate": 700, "company": company + "actual_qty": 10, "incoming_rate": 700, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-25", "posting_time": "03:00", - "actual_qty": -15, "company": company + "actual_qty": -15, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-31", "posting_time": "08:00", - "actual_qty": -20, "company": company + "actual_qty": -20, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2013-01-05", "posting_time": "07:00", - "actual_qty": 15, "incoming_rate": 1200, "company": company + "actual_qty": 15, "incoming_rate": 1200, "company": "_Test Company" }, ] - webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers) \ No newline at end of file + webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers) + + +test_dependencies = ["Item", "Warehouse"] \ No newline at end of file From e68103be30eef0ccb840fc18980518b0e74d5697 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:34:47 +0530 Subject: [PATCH 4/7] fixes in reorder level and company --- setup/doctype/company/company.py | 8 +++----- stock/doctype/bin/bin.py | 19 +++++-------------- stock/doctype/item_reorder/item_reorder.txt | 13 ++++++++----- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 405171760b..e895b49fdc 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -47,12 +47,11 @@ class DocType: ['Loans and Advances (Assets)','Current Assets','Group','No','','Debit',self.doc.name,''], ['Securities and Deposits','Current Assets','Group','No','','Debit',self.doc.name,''], ['Earnest Money','Securities and Deposits','Ledger','No','','Debit',self.doc.name,''], - ['Stock In Hand','Current Assets','Group','No','','Debit',self.doc.name,''], - ['Stock','Stock In Hand','Ledger','No','','Debit',self.doc.name,''], - ['Stock Delivered But Not Billed', 'Stock In Hand', 'Ledger', + ['Stock Assets','Current Assets','Group','No','','Debit',self.doc.name,''], + ['Stock In Hand','Stock Assets','Ledger','No','','Debit',self.doc.name,''], + ['Stock Delivered But Not Billed', 'Stock Assets', 'Ledger', 'No', '', 'Debit', self.doc.name, ''], ['Tax Assets','Current Assets','Group','No','','Debit',self.doc.name,''], - ['Stock Delivered But Not Billed','Current Assets','Ledger','No','','Debit',self.doc.name,''], ['Fixed Assets','Application of Funds (Assets)','Group','No','','Debit',self.doc.name,''], ['Capital Equipments','Fixed Assets','Ledger','No','Fixed Asset Account','Debit',self.doc.name,''], ['Computers','Fixed Assets','Ledger','No','Fixed Asset Account','Debit',self.doc.name,''], @@ -111,7 +110,6 @@ class DocType: ['Secured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Unsecured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Bank Overdraft Account','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], - ['Stock Received But Not Billed','Current Liabilities','Ledger','No','','Credit',self.doc.name,''], ['Temporary Accounts (Liabilities)','Source of Funds (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','No','','Credit',self.doc.name,''] ] diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 37ecf85d2c..204053d9ee 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -16,15 +16,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import _ - -from webnotes.utils import add_days, cint, cstr, flt, now, nowdate, \ - get_url_to_form, formatdate -from webnotes.model import db_exists -from webnotes.model.doc import Document, addchild -from webnotes.model.bean import copy_doclist -from webnotes.model.code import get_obj -from webnotes import msgprint +from webnotes.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate +from webnotes import msgprint, _ sql = webnotes.conn.sql import webnotes.defaults @@ -61,7 +54,7 @@ class DocType: from stock.stock_ledger import update_entries_after if not args.get("posting_date"): - posting_date = nowdate() + args["posting_date"] = nowdate() # update valuation and qty after transaction for post dated entry update_entries_after({ @@ -108,11 +101,10 @@ class DocType: #check if re-order is required item_reorder = webnotes.conn.get("Item Reorder", {"parent": self.doc.item_code, "warehouse": self.doc.warehouse}) - if item_reorder: reorder_level = item_reorder.warehouse_reorder_level reorder_qty = item_reorder.warehouse_reorder_qty - material_request_type = item_reorder.material_request_type + material_request_type = item_reorder.material_request_type or "Purchase" else: reorder_level, reorder_qty = webnotes.conn.get_value("Item", self.doc.item_code, ["re_order_level", "re_order_qty"]) @@ -123,7 +115,7 @@ class DocType: material_request_type) def create_material_request(self, doc_type, doc_name, reorder_level, reorder_qty, - material_request_type): + material_request_type="Purchase"): """ Create indent on reaching reorder level """ defaults = webnotes.defaults.get_defaults() item = webnotes.doc("Item", self.doc.item_code) @@ -151,7 +143,6 @@ class DocType: "qty": reorder_qty, "brand": item.brand, }]) - mr.insert() mr.submit() diff --git a/stock/doctype/item_reorder/item_reorder.txt b/stock/doctype/item_reorder/item_reorder.txt index 43ed4fed86..b6933c7458 100644 --- a/stock/doctype/item_reorder/item_reorder.txt +++ b/stock/doctype/item_reorder/item_reorder.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:28:01", + "creation": "2013-03-07 11:42:59", "docstatus": 0, - "modified": "2013-03-07 07:03:22", + "modified": "2013-03-19 12:22:44", "modified_by": "Administrator", "owner": "Administrator" }, @@ -20,7 +20,8 @@ "parent": "Item Reorder", "parentfield": "fields", "parenttype": "DocType", - "permlevel": 0 + "permlevel": 0, + "read_only": 0 }, { "doctype": "DocType", @@ -38,7 +39,8 @@ "doctype": "DocField", "fieldname": "warehouse_reorder_level", "fieldtype": "Float", - "label": "Re-order Level" + "label": "Re-order Level", + "reqd": 1 }, { "doctype": "DocField", @@ -51,6 +53,7 @@ "fieldname": "material_request_type", "fieldtype": "Select", "label": "Material Request Type", - "options": "Purchase\nTransfer" + "options": "Purchase\nTransfer", + "reqd": 1 } ] \ No newline at end of file From d98e511c8b45ac9249fb618fa510ec548711dd79 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:45:02 +0530 Subject: [PATCH 5/7] deafult account creation in company --- setup/doctype/company/company.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index e895b49fdc..6ba7985d6d 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -66,6 +66,7 @@ class DocType: ['Stock Expenses','Direct Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Cost of Goods Sold','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], ['Stock Adjustment','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Expenses Included In Valuation', "Stock Expenses", 'Ledger', 'Yes', 'Expense Account', 'Debit', self.doc.name, ''], ['Indirect Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Advertising and Publicity','Indirect Expenses','Ledger','Yes','Chargeable','Debit',self.doc.name,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], From 80abad2ee0c29eacb2796761da76e0943e549909 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 18:18:52 +0530 Subject: [PATCH 6/7] aii: default account from company --- .../purchase_invoice/purchase_invoice.py | 7 ++- .../doctype/sales_invoice/sales_invoice.py | 7 +-- controllers/accounts_controller.py | 25 +++++---- controllers/stock_controller.py | 2 +- setup/doctype/company/company.py | 5 ++ setup/doctype/company/company.txt | 9 +++- .../global_defaults/global_defaults.txt | 6 +-- stock/doctype/delivery_note/delivery_note.py | 16 +++--- .../purchase_receipt/purchase_receipt.py | 2 +- stock/doctype/stock_entry/stock_entry.js | 50 +++++++++++++++--- .../stock_reconciliation.js | 51 ++++++++++++++----- 11 files changed, 130 insertions(+), 50 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 7722c98a07..b56e2ace10 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -444,6 +444,9 @@ class DocType(BuyingController): # item gl entries stock_item_and_auto_inventory_accounting = False + if auto_inventory_accounting: + stock_acocunt = self.get_default_account("stock_received_but_not_billed") + for item in self.doclist.get({"parentfield": "entries"}): if auto_inventory_accounting and item.item_code in self.stock_items: if flt(item.valuation_rate): @@ -455,7 +458,7 @@ class DocType(BuyingController): gl_entries.append( self.get_gl_dict({ - "account": "Stock Received But Not Billed - %s" % (self.company_abbr,), + "account": stock_acocunt, "against": self.doc.credit_to, "debit": flt(item.valuation_rate) * flt(item.conversion_factor) \ * flt(item.qty), @@ -480,7 +483,7 @@ class DocType(BuyingController): # this will balance out valuation amount included in cost of goods sold gl_entries.append( self.get_gl_dict({ - "account": "Expenses Included In Valuation - %s" % (self.company_abbr,), + "account": self.get_default_account("expenses_included_in_valuation"), "cost_center": "Auto Inventory Accounting - %s" % self.company_abbr, "against": self.doc.credit_to, "credit": valuation_tax, diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index b6b1f0ba10..f81a71b1a4 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -704,9 +704,9 @@ class DocType(SellingController): if auto_inventory_accounting: if cint(self.doc.is_pos) and cint(self.doc.update_stock): - stock_account = self.get_stock_in_hand_account() + stock_account = self.get_default_account("stock_in_hand_account") else: - stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) + stock_account = self.get_default_account("stock_delivered_but_not_billed") for item in self.doclist.get({"parentfield": "entries"}): # income account gl entries @@ -794,7 +794,8 @@ class DocType(SellingController): stock_ledger_entries = item_sales_bom = None for item in self.doclist.get({"parentfield": "entries"}): - if item.item_code in self.stock_items: + if item.item_code in self.stock_items or \ + (item_sales_bom and item_sales_bom.get(item.item_code)): item.buying_amount = self.get_item_buying_amount(item, stock_ledger_entries, item_sales_bom) webnotes.conn.set_value("Sales Invoice Item", item.name, diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 66a5d9e09e..df78212cd1 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -71,15 +71,15 @@ class AccountsController(TransactionBase): "advance_amount": flt(d.amount), "allocate_amount": 0 }) - - def get_stock_in_hand_account(self): - stock_in_hand_account = webnotes.conn.get_value("Company", self.doc.company, "stock_in_hand_account") - if not stock_in_hand_account: - msgprint(_("Missing") + ": " - + _(webnotes.get_doctype("company").get_label("stock_in_hand_account") - + " " + _("for Company") + " " + self.doc.company), raise_exception=True) - return stock_in_hand_account + def get_default_account(self, account_for): + account = webnotes.conn.get_value("Company", self.doc.company, account_for) + if not account: + msgprint(_("Please mention default account for '") + + _(webnotes.get_doctype("company").get_label(account_for) + + _("' in Company: ") + self.doc.company), raise_exception=True) + + return account @property def stock_items(self): @@ -88,7 +88,7 @@ class AccountsController(TransactionBase): self._stock_items = [r[0] for r in webnotes.conn.sql("""select name from `tabItem` where name in (%s) and is_stock_item='Yes'""" % \ (", ".join((["%s"]*len(item_codes))),), item_codes)] - + return self._stock_items @property @@ -96,4 +96,9 @@ class AccountsController(TransactionBase): if not hasattr(self, "_abbr"): self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - return self._abbr \ No newline at end of file + return self._abbr + + +@webnotes.whitelist() +def get_default_account(account_for, company): + return webnotes.conn.get_value("Company", company, account_for) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index 3a900aa8be..eec7352f1a 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -20,7 +20,7 @@ from controllers.accounts_controller import AccountsController class StockController(AccountsController): def make_gl_entries(self, against_stock_account, amount, cost_center=None): - stock_in_hand_account = self.get_stock_in_hand_account() + stock_in_hand_account = self.get_default_account("stock_in_hand_account") if amount: gl_entries = [ diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 6ba7985d6d..15241a2ba6 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -214,6 +214,11 @@ class DocType: "Stock Adjustment - " + self.doc.abbr): webnotes.conn.set(self.doc, "stock_adjustment_account", "Stock Adjustment - " + self.doc.abbr) + + if not self.doc.expenses_included_in_valuation and webnotes.conn.exists("Account", + "Expenses Included In Valuation - " + self.doc.abbr): + webnotes.conn.set(self.doc, "expenses_included_in_valuation", + "Expenses Included In Valuation - " + self.doc.abbr) # Create default cost center # --------------------------------------------------- diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt index d8c649ff28..4d2dcdae68 100644 --- a/setup/doctype/company/company.txt +++ b/setup/doctype/company/company.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-27 09:38:05", "docstatus": 0, - "modified": "2013-03-18 16:34:04", + "modified": "2013-03-19 12:52:00", "modified_by": "Administrator", "owner": "Administrator" }, @@ -194,6 +194,13 @@ "label": "Stock Adjustment Account", "options": "Account" }, + { + "doctype": "DocField", + "fieldname": "expenses_included_in_valuation", + "fieldtype": "Link", + "label": "Expenses Included In Valuation", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "col_break23", diff --git a/setup/doctype/global_defaults/global_defaults.txt b/setup/doctype/global_defaults/global_defaults.txt index 960da7e231..d75f1efe88 100644 --- a/setup/doctype/global_defaults/global_defaults.txt +++ b/setup/doctype/global_defaults/global_defaults.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-19 12:28:27", + "creation": "2013-02-21 14:54:43", "docstatus": 0, - "modified": "2013-02-20 14:09:00", + "modified": "2013-03-19 14:46:49", "modified_by": "Administrator", "owner": "Administrator" }, @@ -403,7 +403,7 @@ "fieldname": "emp_created_by", "fieldtype": "Select", "label": "Employee Records to be created by ", - "options": "\nNaming Series\nEmployee Number" + "options": "Naming Series\nEmployee Number" }, { "doctype": "DocField", diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index aef79390c2..62d5c5f8b2 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -400,12 +400,14 @@ class DocType(SellingController): if stock_ledger_entries: for item in self.doclist.get({"parentfield": "delivery_note_details"}): - buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, - self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, - item_sales_bom) - item.buying_amount = buying_amount > 0 and buying_amount or 0 - webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", - item.buying_amount) + if item.item_code in self.stock_items or \ + (item_sales_bom and item_sales_bom.get(item.item_code)): + buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, + self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, + item_sales_bom) + item.buying_amount = buying_amount > 0 and buying_amount or 0 + webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", + item.buying_amount) self.validate_warehouse() @@ -420,7 +422,7 @@ class DocType(SellingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - against_stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) + against_stock_account = self.get_default_account("stock_delivered_but_not_billed") total_buying_amount = self.get_total_buying_amount() super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index e26c0a6d1e..e7d030d719 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -318,7 +318,7 @@ class DocType(BuyingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - against_stock_account = "Stock Received But Not Billed - %s" % (self.company_abbr,) + against_stock_account = self.get_default_account("stock_received_but_not_billed") total_valuation_amount = self.get_total_valuation_amount() super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index 0a75914a62..2eb538c53d 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -18,6 +18,47 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ + onload: function() { + this.set_default_account(); + }, + + set_default_account: function() { + var me = this; + + if (sys_defaults.auto_inventory_accounting && !this.frm.doc.expense_adjustment_account) { + if (this.frm.doc.purpose == "Sales Return") + account_for = "stock_delivered_but_not_billed"; + else if (this.frm.doc.purpose == "Purchase Return") + account_for = "stock_received_but_not_billed"; + else account_for = "stock_adjustment_account"; + + this.frm.call({ + method: "controllers.accounts_controller.get_default_account", + args: { + "account_for": account_for, + "company": this.frm.doc.company + }, + callback: function(r) { + if (!r.exc) me.frm.set_value("expense_adjustment_account", r.message); + } + }); + } + }, + + setup: function() { + var me = this; + if (sys_defaults.auto_inventory_accounting) { + this.frm.add_fetch("company", "expense_adjustment_account", "stock_adjustment_account"); + + this.frm.fields_dict["expense_adjustment_account"].get_query = function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { "company": me.frm.doc.company } + } + } + } + }, + onload_post_render: function() { if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) && !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) { @@ -234,11 +275,4 @@ cur_frm.cscript.validate_items = function(doc) { cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query; -cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; - -cur_frm.fields_dict["expense_adjustment_account"].get_query = function(doc) { - return { - "query": "accounts.utils.get_account_list", - "filters": { "company": doc.company } - } -} \ No newline at end of file +cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.js b/stock/doctype/stock_reconciliation/stock_reconciliation.js index fb4053ca9e..372166eaac 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.js +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.js @@ -18,10 +18,44 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ - setup: function() { - this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); + onload: function() { + this.set_default_expense_account(); }, + set_default_expense_account: function() { + var me = this; + + if (sys_defaults.auto_inventory_accounting && !this.frm.doc.expense_account) { + this.frm.call({ + method: "controllers.accounts_controller.get_default_account", + args: { + "account_for": "stock_adjustment_account", + "company": this.frm.doc.company + }, + callback: function(r) { + if (!r.exc) me.frm.set_value("expense_account", r.message); + } + }); + } + }, + + setup: function() { + var me = this; + + this.frm.add_fetch("company", "expense_account", "stock_adjustment_account"); + + this.frm.fields_dict["expense_account"].get_query = function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": me.frm.doc.company + } + } + } + }, + refresh: function() { if(this.frm.doc.docstatus===0) { this.show_download_template(); @@ -126,15 +160,4 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ }, }); -cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); - -cur_frm.fields_dict["expense_account"].get_query = function(doc) { - return { - "query": "accounts.utils.get_account_list", - "filters": { - "is_pl_account": "Yes", - "debit_or_credit": "Debit", - "company": doc.company - } - } -} \ No newline at end of file +cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); \ No newline at end of file From 8803df04ccc9ed1cf39d104d75bcd4e9f41926c1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 18:53:00 +0530 Subject: [PATCH 7/7] aii: get_query for default account in company --- setup/doctype/company/company.js | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/setup/doctype/company/company.js b/setup/doctype/company/company.js index a84bbc9714..a89882347e 100644 --- a/setup/doctype/company/company.js +++ b/setup/doctype/company/company.js @@ -58,3 +58,43 @@ cur_frm.fields_dict.receivables_group.get_query = function(doc) { cur_frm.fields_dict.payables_group.get_query = function(doc) { return 'SELECT `tabAccount`.name FROM `tabAccount` WHERE `tabAccount`.company = "'+doc.name+'" AND `tabAccount`.group_or_ledger = "Group" AND `tabAccount`.docstatus != 2 AND `tabAccount`.%(key)s LIKE "%s" ORDER BY `tabAccount`.name LIMIT 50'; } + + +cur_frm.fields_dict["stock_in_hand_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Debit", + "company": doc.name + } + } +} + +cur_frm.fields_dict["stock_adjustment_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.name + } + } +} + +cur_frm.fields_dict["expenses_included_in_valuation"].get_query = + cur_frm.fields_dict["stock_adjustment_account"].get_query; + +cur_frm.fields_dict["stock_delivered_but_not_billed"].get_query = + cur_frm.fields_dict["stock_in_hand_account"].get_query; + +cur_frm.fields_dict["stock_received_but_not_billed"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Credit", + "company": doc.name + } + } +} \ No newline at end of file