From c3afb256b450cbceab5b427297a80774ac4d3b52 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:01:24 +0530 Subject: [PATCH] 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():