From 86a824c7670ae15b24d3d2d9d2d11b07a3acea8c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 15 Apr 2016 16:44:44 +0530 Subject: [PATCH] [ux] added opening stock and rate in new Item --- erpnext/__init__.py | 23 +++++ erpnext/setup/setup_wizard/setup_wizard.py | 2 +- erpnext/stock/doctype/item/item.json | 63 ++++++++++++-- erpnext/stock/doctype/item/item.py | 39 +++++++++ .../doctype/stock_entry/stock_entry_utils.py | 46 ++++++++++ .../doctype/stock_entry/test_stock_entry.py | 43 +-------- .../doctype/stock_settings/stock_settings.js | 8 ++ .../stock_settings/stock_settings.json | 87 ++++++++++++++++++- erpnext/stock/reorder_item.py | 3 +- 9 files changed, 262 insertions(+), 52 deletions(-) create mode 100644 erpnext/stock/doctype/stock_entry/stock_entry_utils.py create mode 100644 erpnext/stock/doctype/stock_settings/stock_settings.js diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 60bec4fbec..5324cde537 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -1 +1,24 @@ from erpnext.__version__ import __version__ + +import frappe + +def get_default_company(user=None): + '''Get default company for user''' + from frappe.defaults import get_user_default_as_list + + if not user: + user = frappe.session.user + + companies = get_user_default_as_list(user, 'company') + if companies: + default_company = companies[0] + else: + default_company = frappe.db.get_single_value('Global Defaults', 'default_company') + + return default_company + +def get_default_currency(): + '''Returns the currency of the default company''' + company = get_default_company() + if company: + return frappe.db.get_value('Company', company, 'default_currency') \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index 542eb0b9e3..a21fd21ace 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -10,7 +10,6 @@ from frappe.utils.file_manager import save_file from .default_website import website_maker import install_fixtures from .sample_data import make_sample_data -from erpnext.accounts.utils import FiscalYearError from erpnext.accounts.doctype.account.account import RootNotEditable from frappe.core.doctype.communication.comment import add_info_comment @@ -136,6 +135,7 @@ def set_defaults(args): stock_settings = frappe.get_doc("Stock Settings") stock_settings.item_naming_by = "Item Code" stock_settings.valuation_method = "FIFO" + stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')}) stock_settings.stock_uom = _("Nos") stock_settings.auto_indent = 1 stock_settings.auto_insert_price_list_rate_if_missing = 1 diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index c1fad75c71..a85bb89623 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -222,6 +222,31 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "disabled", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Disabled", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -283,16 +308,42 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, - "fieldname": "disabled", - "fieldtype": "Check", + "depends_on": "__islocal", + "fieldname": "opening_stock", + "fieldtype": "Int", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Disabled", + "label": "Opening Stock", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "fieldname": "standard_rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Standard Rate", "length": 0, "no_copy": 0, "permlevel": 0, @@ -2205,7 +2256,7 @@ "issingle": 0, "istable": 0, "max_attachments": 1, - "modified": "2016-04-15 04:53:25.076425", + "modified": "2016-04-15 07:10:24.271811", "modified_by": "Administrator", "module": "Stock", "name": "Item", @@ -2372,7 +2423,7 @@ "write": 0 } ], - "quick_entry": 0, + "quick_entry": 1, "read_only": 0, "read_only_onload": 0, "search_fields": "item_name,description,item_group,customer_code", diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index d8a3115db5..f0e5f29863 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import frappe +import erpnext import json import urllib import itertools @@ -55,6 +56,14 @@ class Item(WebsiteGenerator): self.publish_in_hub = 1 + def after_insert(self): + '''set opening stock and item price''' + if self.standard_rate: + self.add_price() + + if self.opening_stock: + self.set_opening_stock() + def validate(self): super(Item, self).validate() @@ -95,6 +104,36 @@ class Item(WebsiteGenerator): self.update_variants() self.update_template_item() + def add_price(self, price_list=None): + '''Add a new price''' + if not price_list: + price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list') + or frappe.db.get_value('Price List', _('Standard Selling'))) + if price_list: + item_price = frappe.get_doc({ + "doctype": "Item Price", + "price_list": price_list, + "item_code": self.name, + "currency": erpnext.get_default_currency(), + "price_list_rate": self.standard_rate + }) + item_price.insert() + + def set_opening_stock(self): + '''set opening stock''' + from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry + + # default warehouse, or Stores + default_warehouse = (frappe.db.get_single_value('Stock Settings', 'default_warehouse') + or frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})) + + if default_warehouse: + stock_entry = make_stock_entry(item_code=self.name, + target=default_warehouse, + qty=self.opening_stock) + + stock_entry.add_comment("Comment", _("Opening Stock")) + def validate_website_image(self): """Validate if the website image is a public file""" auto_set_website_image = False diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py new file mode 100644 index 0000000000..dcfc304655 --- /dev/null +++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py @@ -0,0 +1,46 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import frappe + +def make_stock_entry(**args): + s = frappe.new_doc("Stock Entry") + args = frappe._dict(args) + if args.posting_date: + s.posting_date = args.posting_date + if args.posting_time: + s.posting_time = args.posting_time + + if not args.purpose: + if args.source and args.target: + s.purpose = "Material Transfer" + elif args.source: + s.purpose = "Material Issue" + else: + s.purpose = "Material Receipt" + else: + s.purpose = args.purpose + + s.company = args.company or "_Test Company" + s.purchase_receipt_no = args.purchase_receipt_no + s.delivery_note_no = args.delivery_note_no + s.sales_invoice_no = args.sales_invoice_no + s.difference_account = args.difference_account or "Stock Adjustment - _TC" + + s.append("items", { + "item_code": args.item or args.item_code or "_Test Item", + "s_warehouse": args.from_warehouse or args.source, + "t_warehouse": args.to_warehouse or args.target, + "qty": args.qty, + "basic_rate": args.basic_rate, + "expense_account": args.expense_account or "Stock Adjustment - _TC", + "conversion_factor": 1.0, + "cost_center": "_Test Cost Center - _TC", + "serial_no": args.serial_no + }) + + if not args.do_not_save: + s.insert() + if not args.do_not_submit: + s.submit() + return s diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 78c1dd2082..d9039822a0 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -12,6 +12,7 @@ from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFre from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation from frappe.tests.test_permissions import set_user_permission_doctypes +from eprnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry def get_sle(**args): condition, values = "", [] @@ -604,48 +605,6 @@ def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None): se.submit() return se -def make_stock_entry(**args): - s = frappe.new_doc("Stock Entry") - args = frappe._dict(args) - if args.posting_date: - s.posting_date = args.posting_date - if args.posting_time: - s.posting_time = args.posting_time - - if not args.purpose: - if args.source and args.target: - s.purpose = "Material Transfer" - elif args.source: - s.purpose = "Material Issue" - else: - s.purpose = "Material Receipt" - else: - s.purpose = args.purpose - - s.company = args.company or "_Test Company" - s.purchase_receipt_no = args.purchase_receipt_no - s.delivery_note_no = args.delivery_note_no - s.sales_invoice_no = args.sales_invoice_no - s.difference_account = args.difference_account or "Stock Adjustment - _TC" - - s.append("items", { - "item_code": args.item or args.item_code or "_Test Item", - "s_warehouse": args.from_warehouse or args.source, - "t_warehouse": args.to_warehouse or args.target, - "qty": args.qty, - "basic_rate": args.basic_rate, - "expense_account": args.expense_account or "Stock Adjustment - _TC", - "conversion_factor": 1.0, - "cost_center": "_Test Cost Center - _TC", - "serial_no": args.serial_no - }) - - if not args.do_not_save: - s.insert() - if not args.do_not_submit: - s.submit() - return s - def get_qty_after_transaction(**args): args = frappe._dict(args) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.js b/erpnext/stock/doctype/stock_settings/stock_settings.js new file mode 100644 index 0000000000..49ce3d8ef7 --- /dev/null +++ b/erpnext/stock/doctype/stock_settings/stock_settings.js @@ -0,0 +1,8 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Stock Settings', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json index 2d6e2b4080..d56daf5630 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.json +++ b/erpnext/stock/doctype/stock_settings/stock_settings.json @@ -17,13 +17,16 @@ "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Item Naming By", + "length": 0, "no_copy": 0, "options": "Item Code\nNaming Series", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -40,13 +43,16 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Default Item Group", + "length": 0, "no_copy": 0, "options": "Item Group", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -62,13 +68,42 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Default Stock UOM", + "length": 0, "no_copy": 0, "options": "UOM", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -84,11 +119,14 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -104,13 +142,16 @@ "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Default Valuation Method", + "length": 0, "no_copy": 0, "options": "FIFO\nMoving Average", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -127,12 +168,15 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Allowance Percent", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -148,12 +192,15 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -169,13 +216,16 @@ "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Auto insert Price List rate if missing", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -191,12 +241,15 @@ "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Allow Negative Stock", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -212,12 +265,15 @@ "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -234,13 +290,16 @@ "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Automatically Set Serial Nos based on FIFO", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -256,12 +315,15 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Auto Material Request", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -277,12 +339,15 @@ "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Raise Material Request when stock reaches re-order level", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -298,12 +363,15 @@ "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Notify by Email on creation of automatic Material Request", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -319,12 +387,15 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Freeze Stock Entries", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -340,12 +411,15 @@ "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Stock Frozen Upto", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -361,12 +435,15 @@ "fieldtype": "Int", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Freeze Stocks Older Than [Days]", + "length": 0, "no_copy": 0, "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -382,13 +459,16 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Role Allowed to edit frozen stock", + "length": 0, "no_copy": 0, "options": "Role", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -406,7 +486,8 @@ "is_submittable": 0, "issingle": 1, "istable": 0, - "modified": "2015-09-03 00:42:16.833424", + "max_attachments": 0, + "modified": "2016-04-15 06:51:47.497431", "modified_by": "Administrator", "module": "Stock", "name": "Stock Settings", @@ -433,6 +514,8 @@ "write": 1 } ], + "quick_entry": 1, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py index c87e3364c5..45319131fa 100644 --- a/erpnext/stock/reorder_item.py +++ b/erpnext/stock/reorder_item.py @@ -2,6 +2,7 @@ # License: GNU General Public License v3. See license.txt import frappe +import erpnext from frappe.utils import flt, nowdate, add_days, cint from frappe import _ @@ -18,7 +19,7 @@ def _reorder_item(): material_requests = {"Purchase": {}, "Transfer": {}} warehouse_company = frappe._dict(frappe.db.sql("""select name, company from `tabWarehouse` where disabled=0""")) - default_company = (frappe.defaults.get_defaults().get("company") or + default_company = (erpnext.get_default_company() or frappe.db.sql("""select name from tabCompany limit 1""")[0][0]) items_to_consider = frappe.db.sql_list("""select name from `tabItem` item