From cca33b2ff0f61578f87f32dcd7bfcfbef93ad987 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 8 Jul 2016 18:24:46 +0530 Subject: [PATCH] [cleanup] --- .../purchase_order_dashboard.py | 12 ++ .../supplier_quotation.json | 6 +- erpnext/demo/data/bom.json | 185 +++++++++++------- erpnext/demo/demo.py | 5 +- erpnext/demo/setup_data.py | 30 ++- erpnext/demo/user/manufacturing.py | 77 ++++++++ erpnext/demo/user/purchase.py | 15 +- erpnext/demo/user/stock.py | 97 +++++++++ erpnext/manufacturing/doctype/bom/bom.py | 11 +- .../doctype/bom_operation/bom_operation.json | 28 ++- .../doctype/operation/operation.js | 8 + .../doctype/operation/operation.json | 18 +- .../production_order/production_order.json | 55 +++--- erpnext/projects/web_form/tasks/tasks.json | 2 +- .../setup/setup_wizard/install_fixtures.py | 5 +- .../stock/doctype/stock_entry/stock_entry.py | 11 +- .../stock/doctype/warehouse/warehouse.json | 5 +- .../stock/doctype/warehouse/warehouse_tree.js | 2 +- ...h_supplier_quotations_are_not_created.json | 30 +-- erpnext/stock/stock_ledger.py | 11 +- 20 files changed, 456 insertions(+), 157 deletions(-) create mode 100644 erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py create mode 100644 erpnext/demo/user/manufacturing.py create mode 100644 erpnext/demo/user/stock.py create mode 100644 erpnext/manufacturing/doctype/operation/operation.js diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py new file mode 100644 index 0000000000..4f1f576830 --- /dev/null +++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py @@ -0,0 +1,12 @@ +from frappe import _ + +data = { + 'docstatus': 1, + 'fieldname': 'purchase_order', + 'transactions': [ + { + 'label': _('Related Documents'), + 'items': ['Purchase Receipt', 'Purchase Invoice', 'Stock Entry'] + }, + ] +} \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json index 9bed98c7ff..56ddd6bdc8 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json @@ -9,6 +9,7 @@ "docstatus": 0, "doctype": "DocType", "document_type": "Document", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -1775,6 +1776,7 @@ "hide_toolbar": 0, "icon": "icon-shopping-cart", "idx": 29, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 1, @@ -1782,7 +1784,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-05-23 15:20:34.288790", + "modified": "2016-07-08 06:48:04.162164", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation", @@ -1845,7 +1847,7 @@ "role": "Purchase User", "set_user_permissions": 0, "share": 1, - "submit": 0, + "submit": 1, "write": 1 }, { diff --git a/erpnext/demo/data/bom.json b/erpnext/demo/data/bom.json index 145c0ba923..1c3f7a9140 100644 --- a/erpnext/demo/data/bom.json +++ b/erpnext/demo/data/bom.json @@ -1,145 +1,178 @@ [ { - "item": "Bearing Assembly", + "item": "Bearing Assembly", "items": [ { - "item_code": "Base Bearing Plate", - "qty": 1.0, + "item_code": "Base Bearing Plate", + "qty": 1.0, "rate": 15.0 - }, + }, { - "item_code": "Bearing Block", - "qty": 1.0, + "item_code": "Bearing Block", + "qty": 1.0, "rate": 10.0 - }, + }, { - "item_code": "Bearing Collar", - "qty": 2.0, + "item_code": "Bearing Collar", + "qty": 2.0, "rate": 20.0 - }, + }, { - "item_code": "Bearing Pipe", - "qty": 1.0, + "item_code": "Bearing Pipe", + "qty": 1.0, "rate": 15.0 - }, + }, { - "item_code": "Upper Bearing Plate", - "qty": 1.0, + "item_code": "Upper Bearing Plate", + "qty": 1.0, "rate": 50.0 } ] - }, + }, { - "item": "Wind Mill A Series", + "item": "Wind Mill A Series", "items": [ { - "item_code": "Base Bearing Plate", - "qty": 1.0, + "item_code": "Base Bearing Plate", + "qty": 1.0, "rate": 15.0 - }, + }, { - "item_code": "Base Plate", - "qty": 1.0, + "item_code": "Base Plate", + "qty": 1.0, "rate": 20.0 - }, + }, { - "item_code": "Bearing Block", - "qty": 1.0, + "item_code": "Bearing Block", + "qty": 1.0, "rate": 10.0 - }, + }, { - "item_code": "Bearing Pipe", - "qty": 1.0, + "item_code": "Bearing Pipe", + "qty": 1.0, "rate": 15.0 - }, + }, { - "item_code": "External Disc", - "qty": 1.0, + "item_code": "External Disc", + "qty": 1.0, "rate": 45.0 - }, + }, { - "item_code": "Shaft", - "qty": 1.0, + "item_code": "Shaft", + "qty": 1.0, "rate": 30.0 - }, + }, { - "item_code": "Wing Sheet", - "qty": 4.0, + "item_code": "Wing Sheet", + "qty": 4.0, "rate": 22.0 } ] - }, + }, { - "item": "Wind MIll C Series", + "item": "Wind MIll C Series", "items": [ { - "item_code": "Base Plate", - "qty": 2.0, + "item_code": "Base Plate", + "qty": 2.0, "rate": 20.0 - }, + }, { - "item_code": "Internal Disc", - "qty": 1.0, + "item_code": "Internal Disc", + "qty": 1.0, "rate": 33.0 - }, + }, { - "item_code": "External Disc", - "qty": 1.0, + "item_code": "External Disc", + "qty": 1.0, "rate": 45.0 - }, + }, { - "item_code": "Bearing Assembly", - "qty": 1.0, + "item_code": "Bearing Assembly", + "qty": 1.0, "rate": 130.0 - }, + }, { - "item_code": "Wing Sheet", - "qty": 3.0, + "item_code": "Wing Sheet", + "qty": 3.0, "rate": 22.0 } ] - }, + }, { - "item": "Wind Turbine", + "item": "Wind Turbine", + "with_operations": 1, + "operations": [ + { + "operation": "Prepare Frame", + "time_in_mins": 30.0, + "workstation": "Drilling Machine 1" + }, + { + "operation": "Setup Fixtures", + "time_in_mins": 15.0, + "workstation": "Assembly Station 1" + }, + { + "operation": "Assembly Operation", + "time_in_mins": 30.0, + "workstation": "Assembly Station 1" + }, + { + "operation": "Wiring", + "time_in_mins": 20.0, + "workstation": "Assembly Station 1" + }, + { + "operation": "Testing", + "time_in_mins": 10.0, + "workstation": "Packing and Testing Station" + }, + { + "operation": "Packing", + "time_in_mins": 25.0, + "workstation": "Packing and Testing Station" + } + ], "items": [ { - "item_code": "Base Bearing Plate", - "qty": 1.0, + "item_code": "Base Bearing Plate", + "qty": 1.0, "rate": 15.0 - }, + }, { - "item_code": "Base Plate", - "qty": 1.0, + "item_code": "Base Plate", + "qty": 1.0, "rate": 20.0 - }, + }, { - "item_code": "Bearing Collar", - "qty": 1.0, + "item_code": "Bearing Collar", + "qty": 1.0, "rate": 20.0 - }, + }, { - "item_code": "Blade Rib", - "qty": 1.0, + "item_code": "Blade Rib", + "qty": 1.0, "rate": 10.0 - }, + }, { - "item_code": "Shaft", - "qty": 1.0, + "item_code": "Shaft", + "qty": 1.0, "rate": 30.0 - }, + }, { - "item_code": "Wing Sheet", - "qty": 2.0, + "item_code": "Wing Sheet", + "qty": 2.0, "rate": 22.0 } ] - }, + }, { - "item": "Base Plate", + "item": "Base Plate", "items": [ { - "item_code": "Base Plate Un Painted", - "qty": 1.0, + "item_code": "Base Plate Un Painted", + "qty": 1.0, "rate": 16.0 } ] diff --git a/erpnext/demo/demo.py b/erpnext/demo/demo.py index ff0f184732..9aeea3a027 100644 --- a/erpnext/demo/demo.py +++ b/erpnext/demo/demo.py @@ -4,7 +4,7 @@ import frappe, sys import erpnext import frappe.utils from erpnext.demo.setup_data import setup_data -from erpnext.demo.user import hr, sales, purchase +from erpnext.demo.user import hr, sales, purchase, manufacturing, stock def make(domain='Manufacturing'): frappe.flags.domain = domain @@ -43,7 +43,8 @@ def simulate(): hr.work() sales.work() purchase.work() - # run_manufacturing() + manufacturing.work() + stock.work() # run_stock() # run_accounts() # run_projects() diff --git a/erpnext/demo/setup_data.py b/erpnext/demo/setup_data.py index 6492152f88..f9bbd5d3c8 100644 --- a/erpnext/demo/setup_data.py +++ b/erpnext/demo/setup_data.py @@ -14,6 +14,7 @@ def setup_data(): setup_customer() setup_supplier() setup_item() + setup_warehouse() import_json('Address') import_json('Contact') setup_workstation() @@ -147,6 +148,11 @@ def setup_item(): item.default_warehouse = frappe.get_all('Warehouse', filters={'warehouse_name': item.default_warehouse}, limit=1)[0].name item.insert() +def setup_warehouse(): + w = frappe.new_doc('Warehouse') + w.warehouse_name = 'Supplier' + w.insert() + def setup_currency_exchange(): frappe.get_doc({ 'doctype': 'Currency Exchange', @@ -182,7 +188,7 @@ def setup_user(): user.password = 'demo' user.insert() -def import_json(doctype, submit=False): +def import_json(doctype, submit=False, values=None): frappe.flags.in_import = True data = json.loads(open(frappe.get_app_path('erpnext', 'demo', 'data', frappe.scrub(doctype) + '.json')).read()) @@ -266,13 +272,14 @@ def setup_salary_structure(): and e.date_of_joining > f.year_start_date) else f.year_start_date ss.to_date = f.year_end_date ss.append('earnings', { - 'earning_type': 'Basic', - 'modified_value': random.random() * 10000 + 'salary_component': 'Basic', + 'amount': random.random() * 10000 }) ss.append('deductions', { - 'deduction_type': 'Income Tax', - 'd_modified_amt': random.random() * 1000 + 'salary_component': 'Income Tax', + 'amount': random.random() * 1000 }) + ss.insert() def setup_account(): @@ -303,5 +310,16 @@ def setup_user_roles(): if not frappe.db.get_global('demo_purchase_user'): user = frappe.get_doc('User', 'MichalSobczak@example.com') - user.add_roles('Purchase User', 'Purchase Manager', 'Accounts User') + user.add_roles('Purchase User', 'Purchase Manager', 'Accounts User', 'Stock User') frappe.db.set_global('demo_purchase_user', user.name) + + if not frappe.db.get_global('demo_manufacturing_user'): + user = frappe.get_doc('User', 'NuranVerkleij@example.com') + user.add_roles('Manufacturing User', 'Stock User', 'Purchase User', 'Accounts User') + frappe.db.set_global('demo_manufacturing_user', user.name) + + if not frappe.db.get_global('demo_stock_user'): + user = frappe.get_doc('User', 'HatsueKashiwagi@example.com') + user.add_roles('Manufacturing User', 'Stock User', 'Purchase User', 'Accounts User') + frappe.db.set_global('demo_stock_user', user.name) + diff --git a/erpnext/demo/user/manufacturing.py b/erpnext/demo/user/manufacturing.py new file mode 100644 index 0000000000..c91570c898 --- /dev/null +++ b/erpnext/demo/user/manufacturing.py @@ -0,0 +1,77 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe, random, erpnext +from frappe.utils.make_random import how_many +from frappe.desk import query_report + +def work(): + frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) + + from erpnext.projects.doctype.timesheet.timesheet import OverlapError + + ppt = frappe.get_doc("Production Planning Tool", "Production Planning Tool") + ppt.company = erpnext.get_default_company() + ppt.use_multi_level_bom = 1 + ppt.get_items_from = "Sales Order" + ppt.purchase_request_for_warehouse = "Stores - WPL" + ppt.run_method("get_open_sales_orders") + ppt.run_method("get_items") + ppt.run_method("raise_production_orders") + ppt.run_method("raise_material_requests") + frappe.db.commit() + + # submit production orders + for pro in frappe.db.get_values("Production Order", {"docstatus": 0}, "name"): + b = frappe.get_doc("Production Order", pro[0]) + b.wip_warehouse = "Work in Progress - WPL" + b.submit() + frappe.db.commit() + + # submit material requests + for pro in frappe.db.get_values("Material Request", {"docstatus": 0}, "name"): + b = frappe.get_doc("Material Request", pro[0]) + b.submit() + frappe.db.commit() + + # stores -> wip + if random.random() < 0.3: + for pro in query_report.run("Open Production Orders")["result"][:how_many("Stock Entry for WIP")]: + make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture") + + # wip -> fg + if random.random() < 0.3: + for pro in query_report.run("Production Orders in Progress")["result"][:how_many("Stock Entry for FG")]: + make_stock_entry_from_pro(pro[0], "Manufacture") + + # submit time logs + for timesheet in frappe.get_all("Timesheet", ["name"], {"docstatus": 0, + "production_order": ("!=", ""), "to_time": ("<", frappe.flags.current_date)}): + timesheet = frappe.get_doc("Timesheet", timesheet.name) + try: + timesheet.submit() + frappe.db.commit() + except OverlapError: + pass + +def make_stock_entry_from_pro(pro_id, purpose): + from erpnext.manufacturing.doctype.production_order.production_order import make_stock_entry + from erpnext.stock.stock_ledger import NegativeStockError + from erpnext.stock.doctype.stock_entry.stock_entry import IncorrectValuationRateError, \ + DuplicateEntryForProductionOrderError, OperationsNotCompleteError + + try: + st = frappe.get_doc(make_stock_entry(pro_id, purpose)) + st.posting_date = frappe.flags.current_date + st.fiscal_year = str(frappe.flags.current_date.year) + for d in st.get("items"): + d.cost_center = "Main - " + frappe.db.get_value('Company', st.company, 'abbr') + st.insert() + frappe.db.commit() + st.submit() + frappe.db.commit() + except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForProductionOrderError, + OperationsNotCompleteError): + frappe.db.rollback() diff --git a/erpnext/demo/user/purchase.py b/erpnext/demo/user/purchase.py index 58da9d333c..94306773da 100644 --- a/erpnext/demo/user/purchase.py +++ b/erpnext/demo/user/purchase.py @@ -27,6 +27,7 @@ def work(): for mr in frappe.get_all('Material Request', filters={'material_request_type': 'Purchase', 'status': 'Open'}, limit=random.randint(1,6)): + print mr.name if not frappe.get_all('Request for Quotation', filters={'material_request': mr.name}, limit=1): rfq = make_request_for_quotation(mr.name) @@ -59,11 +60,11 @@ def work(): exchange_rate = get_exchange_rate(party_account_currency, company_currency) # make supplier quotations - if random.random() < 0.3: + if random.random() < 0.2: from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation report = "Material Requests for which Supplier Quotations are not created" - for row in query_report.run(report)["result"][:how_many("Supplier Quotation")]: + for row in query_report.run(report)["result"][:random.randint(1, 3)]: if row[0] != "'Total'": sq = frappe.get_doc(make_supplier_quotation(row[0])) sq.transaction_date = frappe.flags.current_date @@ -89,13 +90,15 @@ def work(): po.submit() frappe.db.commit() - if random.random() < 0.3: + if random.random() < 0.2: make_subcontract() def make_material_request(item_code, qty): mr = frappe.new_doc("Material Request") - if frappe.db.get_value('BOM', {'item': item_code, 'is_default': 1, 'is_active': 1}): + variant_of = frappe.db.get_value('Item', item_code, 'variant_of') or item_code + + if frappe.db.get_value('BOM', {'item': variant_of, 'is_default': 1, 'is_active': 1}): mr.material_request_type = 'Manufacture' else: mr.material_request_type = "Purchase" @@ -143,6 +146,6 @@ def make_subcontract(): # transfer material for sub-contract stock_entry = frappe.get_doc(make_stock_entry(po.name, po.items[0].item_code)) - stock_entry.from_warehouse = "Stores - WP" - stock_entry.to_warehouse = "Supplier - WP" + stock_entry.from_warehouse = "Stores - WPL" + stock_entry.to_warehouse = "Supplier - WPL" stock_entry.insert() diff --git a/erpnext/demo/user/stock.py b/erpnext/demo/user/stock.py new file mode 100644 index 0000000000..8266d7e05c --- /dev/null +++ b/erpnext/demo/user/stock.py @@ -0,0 +1,97 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe, random +from frappe.desk import query_report +from erpnext.stock.stock_ledger import NegativeStockError +from erpnext.stock.doctype.serial_no.serial_no import SerialNoRequiredError, SerialNoQtyError + +def work(): + frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) + + make_purchase_receipt() + make_delivery_note() + make_stock_reconciliation() + submit_draft_stock_entries() + +def make_purchase_receipt(): + if random.random() < 0.6: + from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt + report = "Purchase Order Items To Be Received" + po_list =list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="'Total'"]))[:random.randint(1, 10)] + for po in po_list: + pr = frappe.get_doc(make_purchase_receipt(po)) + + if pr.is_subcontracted=="Yes": + pr.supplier_warehouse = "Supplier - WPL" + + pr.posting_date = frappe.flags.current_date + pr.insert() + try: + pr.submit() + frappe.db.commit() + except (NegativeStockError): + frappe.db.rollback() + +def make_delivery_note(): + # make purchase requests + + # make delivery notes (if possible) + if random.random() < 0.3: + from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + report = "Ordered Items To Be Delivered" + for so in list(set([r[0] for r in query_report.run(report)["result"] + if r[0]!="'Total'"]))[:random.randint(1, 3)]: + dn = frappe.get_doc(make_delivery_note(so)) + dn.posting_date = frappe.flags.current_date + for d in dn.get("items"): + if not d.expense_account: + d.expense_account = ("Cost of Goods Sold - {0}".format( + frappe.db.get_value('Company', dn.company, 'abbr'))) + dn.insert() + try: + dn.submit() + frappe.db.commit() + except (NegativeStockError, SerialNoRequiredError, SerialNoQtyError): + frappe.db.rollback() + +def make_stock_reconciliation(): + # random set some items as damaged + from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation \ + import OpeningEntryAccountError, EmptyStockReconciliationItemsError + + if random.random() < 0.1: + stock_reco = frappe.new_doc("Stock Reconciliation") + stock_reco.posting_date = frappe.flags.current_date + stock_reco.get_items_for("Stores - WP") + if stock_reco.items: + for item in stock_reco.items: + if item.qty: + item.qty = item.qty - round(random.randint(1, item.qty)) + try: + stock_reco.insert() + stock_reco.submit() + frappe.db.commit() + except OpeningEntryAccountError: + frappe.db.rollback() + except EmptyStockReconciliationItemsError: + frappe.db.rollback() + +def submit_draft_stock_entries(): + from erpnext.stock.doctype.stock_entry.stock_entry import IncorrectValuationRateError, \ + DuplicateEntryForProductionOrderError, OperationsNotCompleteError + + # try posting older drafts (if exists) + for st in frappe.db.get_values("Stock Entry", {"docstatus":0}, "name"): + try: + ste = frappe.get_doc("Stock Entry", st[0]) + ste.posting_date = frappe.flags.current_date + ste.save() + ste.submit() + frappe.db.commit() + except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForProductionOrderError, + OperationsNotCompleteError): + frappe.db.rollback() + diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 287ee9b2f7..580d1bae6e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -41,8 +41,8 @@ class BOM(Document): self.validate_materials() self.set_bom_material_details() - self.calculate_cost() self.validate_operations() + self.calculate_cost() def on_update(self): self.check_recursion() @@ -64,7 +64,7 @@ class BOM(Document): self.manage_default_bom() def get_item_det(self, item_code): - item = frappe.db.sql("""select name, item_name, docstatus, description, image, + item = frappe.db.sql("""select name, item_name, docstatus, description, image, is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate from `tabItem` where name=%s""", item_code, as_dict = 1) @@ -370,7 +370,12 @@ class BOM(Document): def validate_operations(self): if self.with_operations and not self.get('operations'): - frappe.throw(_("Operations cannot be left blank.")) + frappe.throw(_("Operations cannot be left blank")) + + if self.with_operations: + for d in self.operations: + if not d.description: + d.description = frappe.db.get_value('Operation', d.operation, 'description') def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1): item_dict = {} diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json index 0171c41df6..18ab2514a7 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json @@ -2,10 +2,13 @@ "allow_copy": 0, "allow_import": 0, "allow_rename": 0, + "beta": 0, "creation": "2013-02-22 01:27:49", "custom": 0, "docstatus": 0, "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -15,6 +18,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Operation", @@ -25,6 +29,7 @@ "options": "Operation", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -40,6 +45,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Workstation", @@ -50,6 +56,7 @@ "options": "Workstation", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -65,18 +72,20 @@ "fieldtype": "Text Editor", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, - "label": "Operation Description", + "label": "Description", "length": 0, "no_copy": 0, "oldfieldname": "opn_description", "oldfieldtype": "Text", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -89,12 +98,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, @@ -110,6 +121,7 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Hour Rate", @@ -119,6 +131,7 @@ "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -135,6 +148,7 @@ "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "label": "Operation Time ", @@ -145,6 +159,7 @@ "options": "", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 1, @@ -160,6 +175,7 @@ "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Operating Cost", @@ -169,6 +185,7 @@ "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, "reqd": 0, @@ -180,18 +197,21 @@ "hide_heading": 0, "hide_toolbar": 0, "idx": 1, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-16 06:29:42.924201", + "modified": "2016-07-08 08:42:17.903362", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operation", "owner": "Administrator", "permissions": [], + "quick_entry": 0, "read_only": 0, - "read_only_onload": 0 + "read_only_onload": 0, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/operation/operation.js b/erpnext/manufacturing/doctype/operation/operation.js new file mode 100644 index 0000000000..5c2aba6f09 --- /dev/null +++ b/erpnext/manufacturing/doctype/operation/operation.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('Operation', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/manufacturing/doctype/operation/operation.json b/erpnext/manufacturing/doctype/operation/operation.json index 66d0bb6fc1..bf7f519be9 100644 --- a/erpnext/manufacturing/doctype/operation/operation.json +++ b/erpnext/manufacturing/doctype/operation/operation.json @@ -3,11 +3,13 @@ "allow_import": 1, "allow_rename": 1, "autoname": "Prompt", + "beta": 0, "creation": "2014-11-07 16:20:30.683186", "custom": 0, "docstatus": 0, "doctype": "DocType", "document_type": "Setup", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -17,6 +19,7 @@ "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 1, "label": "Default Workstation", @@ -26,6 +29,7 @@ "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -41,6 +45,7 @@ "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "length": 0, @@ -48,6 +53,7 @@ "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -63,14 +69,16 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Operation Description", + "label": "Description", "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, @@ -82,13 +90,15 @@ "hide_heading": 0, "hide_toolbar": 0, "icon": "icon-wrench", + "idx": 0, + "image_view": 0, "in_create": 0, "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2015-11-16 06:29:50.879598", + "modified": "2016-07-08 08:42:35.126397", "modified_by": "Administrator", "module": "Manufacturing", "name": "Operation", @@ -136,8 +146,10 @@ "write": 1 } ], + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_order/production_order.json b/erpnext/manufacturing/doctype/production_order/production_order.json index 1a5415f298..d1dc0c2ed7 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.json +++ b/erpnext/manufacturing/doctype/production_order/production_order.json @@ -9,6 +9,7 @@ "docstatus": 0, "doctype": "DocType", "document_type": "Setup", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -197,6 +198,32 @@ "unique": 0, "width": "50%" }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "", + "fieldname": "sales_order", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Order", + "length": 0, + "no_copy": 0, + "options": "Sales Order", + "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, @@ -948,32 +975,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "description": "Manufacture against Sales Order", - "fieldname": "sales_order", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Sales Order", - "length": 0, - "no_copy": 0, - "options": "Sales Order", - "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, @@ -1091,7 +1092,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-07-06 16:09:38.879785", + "modified": "2016-07-08 07:09:06.847763", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Order", diff --git a/erpnext/projects/web_form/tasks/tasks.json b/erpnext/projects/web_form/tasks/tasks.json index 912b4c4c1d..1d952fc074 100644 --- a/erpnext/projects/web_form/tasks/tasks.json +++ b/erpnext/projects/web_form/tasks/tasks.json @@ -11,7 +11,7 @@ "idx": 0, "is_standard": 1, "login_required": 1, - "modified": "2016-06-24 16:11:10.935835", + "modified": "2016-07-07 06:04:30.979390", "modified_by": "Administrator", "module": "Projects", "name": "tasks", diff --git a/erpnext/setup/setup_wizard/install_fixtures.py b/erpnext/setup/setup_wizard/install_fixtures.py index f2b72f4ff1..3ea2539ba1 100644 --- a/erpnext/setup/setup_wizard/install_fixtures.py +++ b/erpnext/setup/setup_wizard/install_fixtures.py @@ -183,7 +183,10 @@ def install(country=None): {"doctype": "Offer Term", "offer_term": _("Incentives")}, {'doctype': "Print Heading", 'print_heading': _("Credit Note")}, - {'doctype': "Print Heading", 'print_heading': _("Debit Note")} + {'doctype': "Print Heading", 'print_heading': _("Debit Note")}, + + {"doctype": "Salary Component", "salary_component": _("Basic")}, + {"doctype": "Salary Component", "salary_component": _("Income Tax")}, ] from erpnext.setup.setup_wizard.industry_type import get_industry_types diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 05435f4ae2..9ed005eace 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import frappe.defaults from frappe import _ -from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate +from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate, formatdate, format_time from erpnext.stock.utils import get_incoming_rate from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError from erpnext.stock.get_item_details import get_bin_details, get_default_cost_center, get_conversion_factor @@ -225,9 +225,12 @@ class StockEntry(StockController): # validate qty during submit if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty: - frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}. - Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse, - self.posting_date, self.posting_time, d.actual_qty, d.transfer_qty), NegativeStockError) + frappe.throw(_("Row {0}: Qty not available for {4} in warehouse {1} at posting time of the entry ({2} {3})".format(d.idx, + frappe.bold(d.s_warehouse), formatdate(self.posting_date), + format_time(self.posting_time), frappe.bold(d.item_code))) + + '

' + _("Available qty is {0}, you need {1}").format(frappe.bold(d.actual_qty), + frappe.bold(d.transfer_qty)), + NegativeStockError, title=_('Insufficient Stock')) def get_stock_and_rate(self): self.set_transfer_qty() diff --git a/erpnext/stock/doctype/warehouse/warehouse.json b/erpnext/stock/doctype/warehouse/warehouse.json index 86516ff3ee..192afbb9c9 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.json +++ b/erpnext/stock/doctype/warehouse/warehouse.json @@ -9,6 +9,7 @@ "docstatus": 0, "doctype": "DocType", "document_type": "Setup", + "editable_grid": 0, "fields": [ { "allow_on_submit": 0, @@ -428,7 +429,7 @@ "bold": 0, "collapsible": 0, "fieldname": "pin", - "fieldtype": "Int", + "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -588,7 +589,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-06-29 19:47:24.336215", + "modified": "2016-07-08 06:00:36.113988", "modified_by": "Administrator", "module": "Stock", "name": "Warehouse", diff --git a/erpnext/stock/doctype/warehouse/warehouse_tree.js b/erpnext/stock/doctype/warehouse/warehouse_tree.js index 0134ca7712..0baed4d859 100644 --- a/erpnext/stock/doctype/warehouse/warehouse_tree.js +++ b/erpnext/stock/doctype/warehouse/warehouse_tree.js @@ -14,7 +14,7 @@ frappe.treeview_settings['Warehouse'] = { {fieldtype:'Data', fieldname: 'name_field', label:__('New Warehouse Name'), reqd:true}, {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'), - description: __("Further nodes can be only created under 'Group' type nodes")} + description: __("Child nodes can be only created under 'Group' type nodes")} ], onrender: function(node) { if (node.data && node.data.balance!==undefined) { diff --git a/erpnext/stock/report/material_requests_for_which_supplier_quotations_are_not_created/material_requests_for_which_supplier_quotations_are_not_created.json b/erpnext/stock/report/material_requests_for_which_supplier_quotations_are_not_created/material_requests_for_which_supplier_quotations_are_not_created.json index 55583a9437..86156843d4 100644 --- a/erpnext/stock/report/material_requests_for_which_supplier_quotations_are_not_created/material_requests_for_which_supplier_quotations_are_not_created.json +++ b/erpnext/stock/report/material_requests_for_which_supplier_quotations_are_not_created/material_requests_for_which_supplier_quotations_are_not_created.json @@ -1,17 +1,19 @@ { - "apply_user_permissions": 1, - "creation": "2013-08-09 12:20:58", - "docstatus": 0, - "doctype": "Report", - "idx": 1, - "is_standard": "Yes", - "modified": "2015-03-30 05:46:11.917037", - "modified_by": "Administrator", - "module": "Stock", - "name": "Material Requests for which Supplier Quotations are not created", - "owner": "Administrator", - "query": "select \n mr.name as \"Material Request:Link/Material Request:120\",\n mr.transaction_date as \"Date:Date:100\",\n\tmr_item.item_code as \"Item Code:Link/Item:120\",\n\tmr_item.qty as \"Qty:Float:100\",\n\tmr_item.item_name as \"Item Name::150\",\n\tmr_item.description as \"Description::200\",\n\tmr.company as \"Company:Link/Company:\"\nfrom\n\t`tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere\n\tmr_item.parent = mr.name\n\tand mr.material_request_type = \"Purchase\"\n\tand mr.docstatus = 1\n\tand mr.status != \"Stopped\"\n\tand not exists(select name from `tabSupplier Quotation Item` where prevdoc_docname=mr.name)\norder by mr.transaction_date asc", - "ref_doctype": "Material Request", - "report_name": "Material Requests for which Supplier Quotations are not created", + "add_total_row": 0, + "apply_user_permissions": 1, + "creation": "2013-08-09 12:20:58", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 1, + "is_standard": "Yes", + "modified": "2016-07-08 05:43:10.236943", + "modified_by": "Administrator", + "module": "Stock", + "name": "Material Requests for which Supplier Quotations are not created", + "owner": "Administrator", + "query": "select \n mr.name as \"Material Request:Link/Material Request:120\",\n mr.transaction_date as \"Date:Date:100\",\n\tmr_item.item_code as \"Item Code:Link/Item:120\",\n\tmr_item.qty as \"Qty:Float:100\",\n\tmr_item.item_name as \"Item Name::150\",\n\tmr_item.description as \"Description::200\",\n\tmr.company as \"Company:Link/Company:\"\nfrom\n\t`tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere\n\tmr_item.parent = mr.name\n\tand mr.material_request_type = \"Purchase\"\n\tand mr.docstatus = 1\n\tand mr.status != \"Stopped\"\n\tand not exists(select name from `tabSupplier Quotation Item` where material_request=mr.name)\norder by mr.transaction_date asc", + "ref_doctype": "Material Request", + "report_name": "Material Requests for which Supplier Quotations are not created", "report_type": "Query Report" } \ No newline at end of file diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 096a5e0ed7..8d17a1eee3 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -229,7 +229,7 @@ class update_entries_after(object): # calculate new valuation rate only if stock value is positive # else it remains the same as that of previous entry self.valuation_rate = new_stock_value / new_stock_qty - + def get_moving_average_values(self, sle): actual_qty = flt(sle.actual_qty) new_stock_qty = flt(self.qty_after_transaction) + actual_qty @@ -303,7 +303,7 @@ class update_entries_after(object): break else: index = 0 - + # select first batch or the batch with same rate batch = self.stock_queue[index] if qty_to_pop >= batch[0]: @@ -327,7 +327,7 @@ class update_entries_after(object): if stock_qty: self.valuation_rate = stock_value / flt(stock_qty) - + if not self.stock_queue: self.stock_queue.append([0, sle.incoming_rate or sle.outgoing_rate or self.valuation_rate]) @@ -346,8 +346,9 @@ class update_entries_after(object): - if frappe.local.flags.currently_saving.doctype==self.exceptions[0]["voucher_type"] \ - and frappe.local.flags.currently_saving.name==self.exceptions[0]["voucher_no"]: + if (frappe.local.flags.currently_saving + and frappe.local.flags.currently_saving.doctype==self.exceptions[0]["voucher_type"] + and frappe.local.flags.currently_saving.name==self.exceptions[0]["voucher_no"]): msg = _("{0} units of {1} needed in {2} to complete this transaction.").format( abs(deficiency), frappe.get_desk_link('Item', self.item_code), frappe.get_desk_link('Warehouse', self.warehouse))