From 1859d9d49eb17862dc3ed0769f713445fe576ca4 Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 3 Oct 2013 16:54:26 +0530 Subject: [PATCH 01/43] [docs] 5 step setup folder added --- docs/user/docs.user.md | 7 +- .../five_step_setup/docs.user.five.day_1.md | 85 +++++++++++++++++++ .../five_step_setup/docs.user.five.day_2.md | 53 ++++++++++++ docs/user/five_step_setup/docs.user.five.md | 46 ++++++++++ .../setup/docs.user.setup.cost_centers.md | 8 ++ docs/user/setup/docs.user.setup.users.md | 2 +- docs/user/stock/docs.user.stock.item.md | 2 +- 7 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_1.md create mode 100644 docs/user/five_step_setup/docs.user.five.day_2.md create mode 100644 docs/user/five_step_setup/docs.user.five.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index c45ca30a22..82e211f1ce 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -3,6 +3,7 @@ "_label": "User Guide", "_toc": [ "docs.user.intro", + "docs.user.five", "docs.user.implement", "docs.user.setup", "docs.user.selling", @@ -17,7 +18,7 @@ "docs.user.tools", "docs.user.customize", "docs.user.knowledge" - ], + ], "_no_toc": 1 } --- @@ -29,6 +30,9 @@ Contents 1. [Open Source](docs.user.intro.open_source.html) 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) +1. [Five-Day-Setup](docs.user.five.html) + 1. [Day-1](docs.user.five.day_1.html) + 1. [Day-2](docs.user.five.day_2.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) @@ -154,4 +158,3 @@ Contents 1. [DocType Definitions](docs.user.knowledge.doctype.html) 1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html) 1. [Format using Markdown](docs.user.knowledge.markdown.html) - diff --git a/docs/user/five_step_setup/docs.user.five.day_1.md b/docs/user/five_step_setup/docs.user.five.day_1.md new file mode 100644 index 0000000000..d6786b40da --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_1.md @@ -0,0 +1,85 @@ +--- +{ + "_label": "Day-1" +} +--- +Login to your ERPNext account with the User ID and Password sent through the mail. + +After logging into your account you will receive a pop-up form to fill. Please fill this form. Select the abbreviation you would wish to have for your company. The abbreviation selected here will be used in naming most of the business documents. + +#### Form Part I + +![1st Form](img/firstdaysetup_1.png) +
+#### Form Part II +
+ +To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) + + +![1st Form](img/firstdaysetup_2.png) + +After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear. + +
+#### Setup Page - Customer + +The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon. + +![Customer](img/firstdaysetup_customer.png) +
+ + +After clicking on Customer, a new form will appear. +
+ +![Customer](img/firstdaysetup_customer_1.png) + +To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system. + +Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup + +![Main Menu](img/firstdaysetup_main_menu.png) + +
+ +#### Setup Page - Item + +On the setup page go to Item. + + +![Item](img/firstdaysetup_item.png) + + +Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers. + +Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item. + +![Item](img/firstdaysetup_item_1.png) + +To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers. + +
+#### Setup Page - Suppliers +
+ +On the Setup page go to Supplier. + +![Supplier](img/firstdaysetup_supplier.png) +
+ +Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record. + +![Supplier](img/firstdaysetup_supplier_1.png) + + +To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html). + +If you wish to import your list of customers and suppliers directly to ERPNext, you can do that via the Data Import Tool. + +To upload Customers or suppliers in bulk, go to the Data Import Tool. + +> Note: The data import format is case-sensitive. The file will not be processed if there are any spelling mistakes or deviations from the default values. + +To understand how to import data, visit [Importing Data](docs.user.setup.data_import.html). + diff --git a/docs/user/five_step_setup/docs.user.five.day_2.md b/docs/user/five_step_setup/docs.user.five.day_2.md new file mode 100644 index 0000000000..c1a5d28cb7 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_2.md @@ -0,0 +1,53 @@ +--- +{ + "_label": "Day-2" +} +--- + +#### Setup Page- Accounts + +Go to the Accounts icon and make ledgers under Chart of Accounts. + +![Accounts](img/seconddaysetup_accounts.png) + +
+ + +Create acccounting ledgers. + +![Tree](img/seconddaysetup_tree.png) + +
+ +To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. + +
+ +![Ledger](img/seconddaysetup_accounts_jv.png) + +
+ + +To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html). + +#### Opening Stock + +You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. + +![Stock Opening](img/seconddaysetup_stock_opening.png) +
+ + +To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html). + + +#### Setup Page - HR Setup + +To setup HR, begin by creating individual employee records. + + +![Employee](img/seconddaysetup_hr.png) + +To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html) + +To complete the remaining HR-Setup, see [Human Resources](docs.user.hr.html) \ No newline at end of file diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md new file mode 100644 index 0000000000..4203fad62a --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.md @@ -0,0 +1,46 @@ +--- +{ + "_label": "Five-Day Setup", + "_toc": [ + "docs.user.five.day_1", + "docs.user.five.day_2" + + ] +} +--- +Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation. + +The setup help is divided into day-wise instructions for 5 consecutive days. Day 1 will cover the following topics: + +#### Day 1 + +- Company Setup +- Customer Setup +- Item Setup +- Supplier Setup +- Data Import Tool + +#### Day 2 + +- Opening Accounts +- Opening Stock +- HR Setup + +#### Day 3 + +- Sales Cycle +- Purchase Cycle +- Manufacturing Cycle + + +#### Day 4 + +- Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc +- Accounts + +#### Day 5 + +- Billing +- Payments +- HR Reports + diff --git a/docs/user/setup/docs.user.setup.cost_centers.md b/docs/user/setup/docs.user.setup.cost_centers.md index 3df26e16a0..d666e4157f 100644 --- a/docs/user/setup/docs.user.setup.cost_centers.md +++ b/docs/user/setup/docs.user.setup.cost_centers.md @@ -45,6 +45,14 @@ ERPNext will help you set and manage budgets on your Cost Centers. This is usefu Budgets are also great for planning purposes. When you are making plans for the next financial year, you would typically target a revenue based on which you would set your expenses. Setting a budget will ensure that your expenses do not get out of hand, at any point, as per your plans. You can define it in the Cost Center. If you have seasonal sales you can also define a budget distribution that the budget will follow. + +> Accounts > Budget Distribution > New Budget Distribution + + +![Budget Distribution](img/budgeting.png) + + +  #### Budget Actions diff --git a/docs/user/setup/docs.user.setup.users.md b/docs/user/setup/docs.user.setup.users.md index 82d79d3d09..06ac9108ec 100644 --- a/docs/user/setup/docs.user.setup.users.md +++ b/docs/user/setup/docs.user.setup.users.md @@ -6,7 +6,7 @@ ERPNext has a role-based permission system, which means that you can assign Roles to Users, and permissions on Roles.Each ERPNext user has a Profile. The Profile contains the user’s email and authentication and can be set from: -> Setup > Users and Permissions > Users +> Setup > Profile #### Step 1: Adding a new User diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index 5ac78d7e51..76a83a2afa 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -15,7 +15,7 @@ ERPNext is optimized for itemized management of your sales and purchase. If you - **Item Name:** Item name is the actual name of your product or service. - **Item Code:** Item Code is a short-form to denote your Item. If you have very few Items, it is advisable to keep the Item Name and the Item Code same. This helps new users to recognise and update Item details in all transactions. In case you have lot of Items with long names and the list runs in hundreds, it is advisable to code. To understand naming Item codes see [Item Codification](docs.user.setup.codification.html) -- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under Item Group. +- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under [Item Group](docs.user.stock.item_group.html) - **Default Unit of Measure:** This is the default measuring unit that you will use for your product. It could be in nos, kgs, meters, etc. You can store all the UOM’s that your product will require under Set Up> Master Data > UOM. These can be preselected while filling New Item by using % sign to get a pop up of the UOM list. - **Brand:** If you have more than one brand save them under Set Up> Master Data> Brand and pre-select them while filling a New Item. From d1809e30e9e81fa468792b1407e7b3f0082048db Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 3 Oct 2013 18:58:11 +0530 Subject: [PATCH 02/43] [minor] [fix] due date in sales invoice --- accounts/doctype/sales_invoice/sales_invoice.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 00c6c2cc5c..516d1925a8 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-09-19 11:42:13", + "modified": "2013-10-03 18:54:31", "modified_by": "Administrator", "owner": "Administrator" }, @@ -180,7 +180,6 @@ "search_index": 1 }, { - "default": "Today", "description": "Enter the date by which payments from customer is expected against this invoice.", "doctype": "DocField", "fieldname": "due_date", From b4212a5672d7f9651f568b19aa7cae679639ae97 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 12:54:16 +0530 Subject: [PATCH 03/43] [patch] [minor] perpetua inventory utility patch --- ...petual_inventory_stock_transfer_utility.py | 71 +++++++++++++++++++ .../set_stock_value_diff_in_sle.py | 10 +++ 2 files changed, 81 insertions(+) create mode 100644 patches/october_2013/perpetual_inventory_stock_transfer_utility.py create mode 100644 patches/october_2013/set_stock_value_diff_in_sle.py diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py new file mode 100644 index 0000000000..f59ebdb55b --- /dev/null +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -0,0 +1,71 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import nowdate, nowtime +from accounts.utils import get_fiscal_year + +def execute(): + item_map = {} + for item in webnotes.conn.sql("""select * from tabItem""", as_dict=1): + item_map.setdefault(item.name, item) + + warehouse_map = get_warehosue_map() + # naming_series = + for company in webnotes.conn.sql("select name from tabCompany"): + stock_entry = [{ + "doctype": "Stock Entry", + "naming_series": naming_series, + "posting_date": nowdate(), + "posting_time": nowtime(), + "purpose": "Material Transfer", + "company": company[0], + "remarks": "Material Transfer to activate perpetual inventory", + "fiscal_year": get_fiscal_year(nowdate()) + }] + expense_account = "Cost of Goods Sold - NISL" + cost_center = "Default CC Ledger - NISL" + + for bin in webnotes.conn.sql("select * from tabBin where company=%s", company[0] as_dict=1): + new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ + if cstr(item_map[bin.item_code]) == "Yes" else wh.get("current_asset_warehouse") + + item_details = item_map[bin.item_code] + stock_entry.append({ + "doctype": "Stock Entry Detail", + "parentfield": "mtn_details", + "s_warehouse": bin.warehouse, + "t_warehouse": new_warehouse, + "item_code": bin.item_code, + "description": item_details.description, + "qty": bin.actual_qty, + "transfer_qty": bin.actual_qty, + "uom": item_details.stock_uom, + "stock_uom": item_details.stock_uom, + "conversion_factor": 1, + "expense_account": expense_account, + "cost_center": cost_center + }) + + webnotes.bean(stock_entry).insert() + +def get_warehosue_map(): + return { + "MAHAPE": { + "current_asset_warehouse": "Mahape-New - NISL", + "fixed_asset_warehouse": "" + }, + "DROP SHIPMENT": { + "current_asset_warehouse": "Drop Shipment-New - NISL", + "fixed_asset_warehouse": "" + }, + "TRANSIT": { + "current_asset_warehouse": "Transit-New - NISL", + "fixed_asset_warehouse": "" + }, + "ASSET-MAHAPE": { + "current_asset_warehouse": "", + "fixed_asset_warehouse": "Assets-New - NISL" + } + } \ No newline at end of file diff --git a/patches/october_2013/set_stock_value_diff_in_sle.py b/patches/october_2013/set_stock_value_diff_in_sle.py new file mode 100644 index 0000000000..25f95e0e6d --- /dev/null +++ b/patches/october_2013/set_stock_value_diff_in_sle.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import cint + +def execute(): + from patches.september_2012 import repost_stock + repost_stock.execute() \ No newline at end of file From b646b3b3e661c55308aa43bd082fa3eebb6be8e2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 14:30:33 +0530 Subject: [PATCH 04/43] [patch] [minor] perpetual inventory stock transfer utility --- ...petual_inventory_stock_transfer_utility.py | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index f59ebdb55b..2b39be69a5 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import nowdate, nowtime +from webnotes.utils import nowdate, nowtime, cstr from accounts.utils import get_fiscal_year def execute(): @@ -12,7 +12,8 @@ def execute(): item_map.setdefault(item.name, item) warehouse_map = get_warehosue_map() - # naming_series = + naming_series = "STE/13/" + for company in webnotes.conn.sql("select name from tabCompany"): stock_entry = [{ "doctype": "Stock Entry", @@ -22,16 +23,28 @@ def execute(): "purpose": "Material Transfer", "company": company[0], "remarks": "Material Transfer to activate perpetual inventory", - "fiscal_year": get_fiscal_year(nowdate()) + "fiscal_year": get_fiscal_year(nowdate())[0] }] expense_account = "Cost of Goods Sold - NISL" cost_center = "Default CC Ledger - NISL" - for bin in webnotes.conn.sql("select * from tabBin where company=%s", company[0] as_dict=1): - new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ - if cstr(item_map[bin.item_code]) == "Yes" else wh.get("current_asset_warehouse") - + for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!='' + and ifnull(warehouse, '')!='' and ifnull(actual_qty, 0) != 0 + and (select company from tabWarehouse where name=bin.warehouse)=%s""", + company[0], as_dict=1): item_details = item_map[bin.item_code] + new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ + if cstr(item_details.is_asset_item) == "Yes" \ + else warehouse_map[bin.warehouse].get("current_asset_warehouse") + + if item_details.has_serial_no == "Yes": + serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name + from `tabSerial No` where item_code = %s and warehouse = %s""", + (bin.item_code, bin.warehouse))]) + print serial_no + else: + serial_no = None + stock_entry.append({ "doctype": "Stock Entry Detail", "parentfield": "mtn_details", @@ -45,9 +58,10 @@ def execute(): "stock_uom": item_details.stock_uom, "conversion_factor": 1, "expense_account": expense_account, - "cost_center": cost_center + "cost_center": cost_center, + "serial_no": serial_no }) - + webnotes.bean(stock_entry).insert() def get_warehosue_map(): @@ -64,7 +78,7 @@ def get_warehosue_map(): "current_asset_warehouse": "Transit-New - NISL", "fixed_asset_warehouse": "" }, - "ASSET-MAHAPE": { + "ASSET - MAHAPE": { "current_asset_warehouse": "", "fixed_asset_warehouse": "Assets-New - NISL" } From 27c9ecc5384394d4ca6080ebf51ea2784078aae9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 14:41:41 +0530 Subject: [PATCH 05/43] [patch] [minor] perpetual inventory stock transfer utility --- .../october_2013/perpetual_inventory_stock_transfer_utility.py | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index 2b39be69a5..c02656285f 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -41,7 +41,6 @@ def execute(): serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name from `tabSerial No` where item_code = %s and warehouse = %s""", (bin.item_code, bin.warehouse))]) - print serial_no else: serial_no = None From 5f8477d4ef7af34d2a6bf54afeb13251ed92dc54 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 15:29:36 +0530 Subject: [PATCH 06/43] [patch] [minor] perpetual inventory stock transfer utility --- .../perpetual_inventory_stock_transfer_utility.py | 4 ++-- stock/doctype/stock_entry/stock_entry.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index c02656285f..8cee29a824 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -39,8 +39,8 @@ def execute(): if item_details.has_serial_no == "Yes": serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name - from `tabSerial No` where item_code = %s and warehouse = %s""", - (bin.item_code, bin.warehouse))]) + from `tabSerial No` where item_code = %s and warehouse = %s + and status='Available'""", (bin.item_code, bin.warehouse))]) else: serial_no = None diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index a54f9bf05b..8c4b97e091 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -42,7 +42,7 @@ class DocType(StockController): self.validate_warehouse(pro_obj) self.validate_production_order(pro_obj) self.get_stock_and_rate() - self.validate_incoming_rate() + # self.validate_incoming_rate() self.validate_bom() self.validate_finished_goods() self.validate_return_reference_doc() From ac90ecf946773bc5fab70a04cd7ed9812e3d1b76 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 15:36:29 +0530 Subject: [PATCH 07/43] [patch] [minor] perpetual inventory stock transfer utility --- stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 8c4b97e091..a54f9bf05b 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -42,7 +42,7 @@ class DocType(StockController): self.validate_warehouse(pro_obj) self.validate_production_order(pro_obj) self.get_stock_and_rate() - # self.validate_incoming_rate() + self.validate_incoming_rate() self.validate_bom() self.validate_finished_goods() self.validate_return_reference_doc() From ecb83e8762bc56bc1f8423dc4b76d1ead4f5c793 Mon Sep 17 00:00:00 2001 From: Priya Date: Fri, 4 Oct 2013 17:18:00 +0530 Subject: [PATCH 08/43] [docs] 5day setup-page 3 added --- docs/user/docs.user.md | 1 + .../five_step_setup/docs.user.five.day_3.md | 135 ++++++++++++++++++ docs/user/five_step_setup/docs.user.five.md | 6 +- .../intro/docs.user.implement.strategy.md | 2 +- 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_3.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 82e211f1ce..098fd89e27 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -33,6 +33,7 @@ Contents 1. [Five-Day-Setup](docs.user.five.html) 1. [Day-1](docs.user.five.day_1.html) 1. [Day-2](docs.user.five.day_2.html) + 1. [Day-3](docs.user.five.day_3.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_3.md b/docs/user/five_step_setup/docs.user.five.day_3.md new file mode 100644 index 0000000000..09a5d3f4ac --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_3.md @@ -0,0 +1,135 @@ +--- +{ + "_label": "Day-3" +} +--- +After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. + + +### Sales Cycle + +Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) + +#### Lead + +To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. + +![Lead](img/thirddaysetup_lead.png) + +Fill the Lead form. + +> To understand Lead in detail, visit [Lead](docs.user.selling.lead.html) + +#### Opportunity + +After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page. + +##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status. + +![Opportunity](img/thirddaysetup_opportunity_1.png) + +
+ +##### Step 2: Generate Opportunity from the selected Lead + +![Opportunity](img/thirddaysetup_opportunity.png) + +You can also generate an Opportunity directly from the Selling Page. + +> To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html). + + +#### Quotation + +Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. + +![Quotation](img/thirddaysetup_quotation.png) + +You can also generate a Quotation directly from the Selling Page. + +> To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html) + + +#### Sales Order + +Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. + +![Sales Order](img/thirddaysetup_sales_order.png) + +You can also generate a Sales Order directly from the Selling Page. + +> To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html). + +#### Delivery Note + +If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. + + +![Delivery Note](img/thirddaysetup_delivery_note.png) + +> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) + + +#### Sales Invoice + +Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. + +![Sales Invoice](img/thirddaysetup_sales_invoice.png) + +
+ +#### Payment (Journal Voucher) + + +A Journal Voucher or a payment entry can be generated directly from the Sales Invoice. + +![Payment Entry](img/thirddaysetup_payment_entry.png) + +> To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) + +
+ +### Purchase Cycle + +Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). + + +#### Material Request + +To create a Material Request, go to Stock/Buying and Click on Material Request. + +![Material Request](img/thirddaysetup-material-request.png) + +> To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html) + +#### Purchase Order + +To create a Purchase Order go to Buying and click on Purchase Order + +![Purchase Order](img/thirddaysetup-purchase-order.png) + +> To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html) + +#### Purchase Receipt + +To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt. + +![Purchase Receipt](img/thirddaysetup-purchase-receipt.png) + +
+ +>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html) + +
+ +#### Payment( Journal Voucher) + +Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices. + + +![Payment Entry](img/thirddaysetup-payment-entry.png) + +
+ +> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). + diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md index 4203fad62a..14b761b31e 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_step_setup/docs.user.five.md @@ -3,7 +3,8 @@ "_label": "Five-Day Setup", "_toc": [ "docs.user.five.day_1", - "docs.user.five.day_2" + "docs.user.five.day_2", + "docs.user.five.day_3" ] } @@ -30,11 +31,12 @@ The setup help is divided into day-wise instructions for 5 consecutive days. Day - Sales Cycle - Purchase Cycle -- Manufacturing Cycle + #### Day 4 +- Manufacturing Cycle - Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc - Accounts diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 9ec58e8874..8f05af7f53 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -13,7 +13,7 @@ Before you start managing your Operations in EPRNext, you must first become fami - Create your first Customer, Supplier and Item. Add a few more so you get familiar with them. - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) -- Complete a standard purchase cycle - Purchase Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). +- Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). - Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush) > Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive. From fb0274b2495b26e8a18e65e64705a05c8e939065 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 14:56:53 +0530 Subject: [PATCH 09/43] [patch] [minor] fix serial no status --- .../october_2013/p01_fix_serial_no_status.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 patches/october_2013/p01_fix_serial_no_status.py diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py new file mode 100644 index 0000000000..8700290fcd --- /dev/null +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -0,0 +1,40 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(): + serial_nos = webnotes.conn.sql("""select name, item_code, status from `tabSerial No` + where status!='Not in Use'""", as_dict=1) + for sr in serial_nos: + last_sle = webnotes.conn.sql("""select voucher_type, voucher_no, actual_qty + from `tabStock Ledger Entry` where serial_no like %s and item_code=%s + order by name desc limit 1""", + ("%%%s%%" % sr.name, sr.item_code), as_dict=1) + + if flt(last_sle[0].actual_qty) > 0: + if last_sle[0].voucher_type == "Stock Entry" and webnotes.conn.get_value("Stock Entry", + last_sle[0].voucher_no, "purpose") == "Sales Return": + status = "Sales Returned" + else: + status = "Available" + else: + if last_sle[0].voucher_type == "Stock Entry": + purpose = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, "purpose") + if purpose == "Purchase Return": + status = "Purchase Returned" + else: + status = "Not Available" + else: + status = "Delivered" + if sr.status != status: + webnotes.conn.sql("""update `tabSerial No` set status=%s where name=%s""", + (status, sr.name)) + + webnotes.conn.sql("""update `tabSerial No` set warehouse='' + where status in ('Delivered', 'Purchase Returned')""") + + + \ No newline at end of file From 0352f9b8270de20684bb70700f85d40e4289a056 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 15:38:43 +0530 Subject: [PATCH 10/43] [fix] [minor] gl entry cancellation --- accounts/doctype/gl_entry/gl_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index db6de44f09..0c11198be9 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -107,7 +107,7 @@ class DocType: _(" does not belong to the company") + ": " + self.doc.company) def check_negative_balance(account, adv_adj=False): - if not adv_adj: + if not adv_adj and account: account_details = webnotes.conn.get_value("Account", account, ["allow_negative_balance", "debit_or_credit"], as_dict=True) if not account_details["allow_negative_balance"]: From 704a915feb29e80377d0adbbb617ca9746bff031 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 17:20:23 +0530 Subject: [PATCH 11/43] [fix] [minor] [delivery note] --- selling/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 801d82bf40..6e74ac4869 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -74,7 +74,7 @@ def get_item_details(args): out.update(apply_pos_settings(pos_settings, out)) if args.doctype in ("Sales Invoice", "Delivery Note"): - if item_bean.doc.has_serial_no and not args.serial_no: + if item_bean.doc.has_serial_no == "Yes" and not args.serial_no: out.serial_no = _get_serial_nos_by_fifo(args, item_bean) return out From 842e9d60cc8118bef78c4e57a6040f69c149989f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 19:57:39 +0530 Subject: [PATCH 12/43] [fix] [minor] serial no update --- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 1c3d3e132d..c29ca3a173 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -166,7 +166,7 @@ class DocType(DocListController): serial_nos.append(self.make_serial_no(make_autoname(item_det.serial_no_series))) self.doc.serial_no = "\n".join(serial_nos) else: - webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item), + webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item_code), SerialNoRequiredError) def make_serial_no(self, serial_no): From e342a75ff96a55a3bccf273efb4d6c99a2e35615 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 7 Oct 2013 12:16:28 +0530 Subject: [PATCH 13/43] [docs] five day setup complete --- docs/user/docs.user.md | 2 + .../five_step_setup/docs.user.five.day_4.md | 96 +++++++++++++++++++ .../five_step_setup/docs.user.five.day_5.md | 34 +++++++ docs/user/five_step_setup/docs.user.five.md | 13 +-- .../intro/docs.user.implement.strategy.md | 2 +- 5 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_4.md create mode 100644 docs/user/five_step_setup/docs.user.five.day_5.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 098fd89e27..3aa3c9e414 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -34,6 +34,8 @@ Contents 1. [Day-1](docs.user.five.day_1.html) 1. [Day-2](docs.user.five.day_2.html) 1. [Day-3](docs.user.five.day_3.html) + 1. [Day-4](docs.user.five.day_4.html) + 1. [Day-5](docs.user.five.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_4.md b/docs/user/five_step_setup/docs.user.five.day_4.md new file mode 100644 index 0000000000..d23fe54585 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_4.md @@ -0,0 +1,96 @@ +--- +{ + "_label": "Day-4" +} +--- + +### Manufacturing Cycle + +Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (material issue) > Stock Entry (sales return) + +#### Bill of Materials + +To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. + +![Bill of Materials](img/fourthdaysetup_bom.png) + +
+ +> To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html) + +#### Production Planning Tool + +To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. + +![Production Planning Page](img/fourthdaysetup_ppt.png) + +
+ +> To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html) + + +#### Production Order + +To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. + +![Production Order](img/fourthdaysetup_po.png) + +
+ +> To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html) + +#### Stock Entry + +To go to Stock Entry, click on the Stock Icon and go to Stock Entry. + +![Stock Entry](img/fourthdaysetup_stock.png) + +
+ +> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html) + + +> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html) + + +#### Delivery Note + +To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. + +[Delivery Note](img/fourthdaysetup_delivery_note.png) + +
+ +> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) + + + +#### Warehouse + +To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. + +![Warehouse](img/fourthdaysetup_warehouse.png) + +
+ +> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) + + +#### Accounts + +Make a few Journal Vouchers. Generate some Accounting Reports. + +#### Journal Voucher. + +To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. + +![Journal Voucher](img/fourthdaysetup_jv.png) + +> To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) + +#### Accounting Reports + +Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register. + +> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) + diff --git a/docs/user/five_step_setup/docs.user.five.day_5.md b/docs/user/five_step_setup/docs.user.five.day_5.md new file mode 100644 index 0000000000..30c64c3708 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_5.md @@ -0,0 +1,34 @@ +--- +{ + "_label": "Day-5" +} +--- + +#### Projects + +ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people. + +#### Tasks + +Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project. + +To create a Task, go to Project and click on Task. + +![Tasks](img/fifthdaysetup_task.png) + +
+ + +> To understand Projects in detail, visit [Projects](docs.user.projects.html) + +> To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html) + +#### Calendar + +> To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html) + + +#### Website + +> To understand Website in detail, visit [Website](docs.user.website.html) + diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md index 14b761b31e..21170c5988 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_step_setup/docs.user.five.md @@ -4,7 +4,9 @@ "_toc": [ "docs.user.five.day_1", "docs.user.five.day_2", - "docs.user.five.day_3" + "docs.user.five.day_3", + "docs.user.five.day_4", + "docs.user.five.day_5" ] } @@ -33,16 +35,15 @@ The setup help is divided into day-wise instructions for 5 consecutive days. Day - Purchase Cycle - #### Day 4 - Manufacturing Cycle -- Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc +- Delivery Note and Warehouse - Accounts #### Day 5 -- Billing -- Payments -- HR Reports +- Projects +- Calendar +- Website diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 8f05af7f53..735fe1e525 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -14,7 +14,7 @@ Before you start managing your Operations in EPRNext, you must first become fami - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) - Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). -- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush) +- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Material Issue > Sales Return > Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive. From 8f05c05bfb96b0a03f1ddbe2ae4e3fdfa951461d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 7 Oct 2013 13:08:13 +0530 Subject: [PATCH 14/43] Validate warehouse for allowed users and matched company --- controllers/buying_controller.py | 19 +++++++----- .../production_order/production_order.py | 29 +++++++++++-------- selling/doctype/sales_order/sales_order.py | 7 +++-- .../material_request/material_request.py | 12 ++------ .../stock_ledger_entry/stock_ledger_entry.py | 12 ++------ stock/utils.py | 7 +++++ 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 7e49e60f8a..25d76aa66d 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -24,7 +24,7 @@ class BuyingController(StockController): self.doc.supplier_name = webnotes.conn.get_value("Supplier", self.doc.supplier, "supplier_name") self.validate_stock_or_nonstock_items() - self.validate_warehouse_belongs_to_company() + self.validate_warehouse() def set_missing_values(self, for_validate=False): super(BuyingController, self).set_missing_values(for_validate) @@ -49,17 +49,20 @@ class BuyingController(StockController): if supplier: self.doc.supplier = supplier break + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + warehouses = list(set([d.warehouse for d in + self.doclist.get({"doctype": self.tname}) if d.warehouse])) + + for w in warehouses: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def get_purchase_tax_details(self): self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details") self.set_taxes("purchase_tax_details", "purchase_other_charges") - - def validate_warehouse_belongs_to_company(self): - for warehouse, company in webnotes.conn.get_values("Warehouse", - self.doclist.get_distinct_values("warehouse"), "company").items(): - if company and company != self.doc.company: - webnotes.msgprint(_("Company mismatch for Warehouse") + (": %s" % (warehouse,)), - raise_exception=WrongWarehouseCompany) def validate_stock_or_nonstock_items(self): if not self.get_stock_items(): diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 6447c0aa12..719d149e64 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -22,13 +22,14 @@ class DocType: utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "In Process", "Completed", "Cancelled"]) - if self.doc.production_item : - item_detail = sql("select name from `tabItem` where name = '%s' and docstatus != 2" - % self.doc.production_item, as_dict = 1) - if not item_detail: - msgprint("Item '%s' does not exist or cancelled in the system." - % cstr(self.doc.production_item), raise_exception=1) - + self.validate_bom_no() + self.validate_sales_order() + self.validate_warehouse() + + from utilities.transaction_base import validate_uom_is_integer + validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) + + def validate_bom_no(self): if self.doc.bom_no: bom = sql("""select name from `tabBOM` where name=%s and docstatus=1 and is_active=1 and item=%s""" @@ -38,16 +39,20 @@ class DocType: May be BOM not exists or inactive or not submitted or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1) + def validate_sales_order(self): if self.doc.sales_order: if not webnotes.conn.sql("""select name from `tabSales Order` where name=%s and docstatus = 1""", self.doc.sales_order): msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1) - + self.validate_production_order_against_so() - - from utilities.transaction_base import validate_uom_is_integer - validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) - + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + for w in [self.doc.fg_warehouse, self.doc.wip_warehouse]: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_production_order_against_so(self): # already ordered qty diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 1ccccdd2eb..435a9768aa 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -127,7 +127,7 @@ class DocType(SellingController): self.validate_po() self.validate_uom_is_integer("stock_uom", "qty") self.validate_for_items() - self.validate_warehouse_user() + self.validate_warehouse() sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_active_sales_items(self) sales_com_obj.check_conversion_rate(self) @@ -148,14 +148,15 @@ class DocType(SellingController): if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered' - def validate_warehouse_user(self): - from stock.utils import validate_warehouse_user + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company warehouses = list(set([d.reserved_warehouse for d in self.doclist.get({"doctype": self.tname}) if d.reserved_warehouse])) for w in warehouses: validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_with_previous_doc(self): super(DocType, self).validate_with_previous_doc(self.tname, { diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index 249062f29d..d1672ba12c 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -68,22 +68,14 @@ class DocType(BuyingController): self.doc.status = "Draft" import utilities - utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", - "Cancelled"]) + utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) - # restrict material request type self.validate_value("material_request_type", "in", ["Purchase", "Transfer"]) - # Get Purchase Common Obj pc_obj = get_obj(dt='Purchase Common') - - - # Validate for items pc_obj.validate_for_items(self) - - # Validate qty against SO - self.validate_qty_against_so() + self.validate_qty_against_so() def update_bin(self, is_submit, is_stopped): """ Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'""" diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index c29ca3a173..6fea546ba6 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -7,7 +7,6 @@ from webnotes import _, msgprint, ValidationError from webnotes.utils import cint, flt, getdate, cstr from webnotes.model.controller import DocListController -class InvalidWarehouseCompany(ValidationError): pass class SerialNoNotRequiredError(ValidationError): pass class SerialNoRequiredError(ValidationError): pass class SerialNoQtyError(ValidationError): pass @@ -25,7 +24,7 @@ class DocType(DocListController): self.doclist = doclist def validate(self): - from stock.utils import validate_warehouse_user + from stock.utils import validate_warehouse_user, validate_warehouse_company if not hasattr(webnotes, "new_stock_ledger_entries"): webnotes.new_stock_ledger_entries = [] @@ -33,7 +32,7 @@ class DocType(DocListController): self.validate_mandatory() self.validate_item() validate_warehouse_user(self.doc.warehouse) - self.validate_warehouse_company() + validate_warehouse_company(self.doc.warehouse, self.doc.company) self.scrub_posting_time() from accounts.utils import validate_fiscal_year @@ -63,13 +62,6 @@ class DocType(DocListController): as on %(posting_date)s %(posting_time)s""" % self.doc.fields) sself.doc.fields.pop('batch_bal') - - def validate_warehouse_company(self): - warehouse_company = webnotes.conn.get_value("Warehouse", self.doc.warehouse, "company") - if warehouse_company and warehouse_company != self.doc.company: - webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ - self.doc.warehouse + ", " + self.doc.company +")", - raise_exception=InvalidWarehouseCompany) def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] diff --git a/stock/utils.py b/stock/utils.py index 8836c6c991..1f501644ff 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -9,6 +9,7 @@ from webnotes.defaults import get_global_default from webnotes.utils.email_lib import sendmail class UserNotAllowedForWarehouse(webnotes.ValidationError): pass +class InvalidWarehouseCompany(webnotes.ValidationError): pass def get_stock_balance_on(warehouse, posting_date=None): if not posting_date: posting_date = nowdate() @@ -216,6 +217,12 @@ def validate_warehouse_user(warehouse): if warehouse_users and not (webnotes.session.user in warehouse_users): webnotes.throw(_("Not allowed entry in Warehouse") \ + ": " + warehouse, UserNotAllowedForWarehouse) + +def validate_warehouse_company(warehouse, company): + warehouse_company = webnotes.conn.get_value("Warehouse", warehouse, "company") + if warehouse_company and warehouse_company != company: + webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ + warehouse + ", " + company +")", raise_exception=InvalidWarehouseCompany) def get_sales_bom_buying_amount(item_code, warehouse, voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries, item_sales_bom): From 172edcecece6539ead608f424c348108ca684a57 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 7 Oct 2013 14:21:04 +0530 Subject: [PATCH 15/43] [docs] five day setup completed --- docs/user/docs.user.md | 14 +++++++------- .../docs.user.five_day_setup.day_1.md} | 8 ++++---- .../docs.user.five_day_setup.day_2.md} | 0 .../docs.user.five_day_setup.day_3.md} | 4 ++-- .../docs.user.five_day_setup.day_4.md} | 8 ++++---- .../docs.user.five_day_setup.day_5.md} | 2 +- .../docs.user.five_day_setup.md} | 12 ++++++------ 7 files changed, 24 insertions(+), 24 deletions(-) rename docs/user/{five_step_setup/docs.user.five.day_1.md => five_day_setup/docs.user.five_day_setup.day_1.md} (94%) rename docs/user/{five_step_setup/docs.user.five.day_2.md => five_day_setup/docs.user.five_day_setup.day_2.md} (100%) rename docs/user/{five_step_setup/docs.user.five.day_3.md => five_day_setup/docs.user.five_day_setup.day_3.md} (97%) rename docs/user/{five_step_setup/docs.user.five.day_4.md => five_day_setup/docs.user.five_day_setup.day_4.md} (92%) rename docs/user/{five_step_setup/docs.user.five.day_5.md => five_day_setup/docs.user.five_day_setup.day_5.md} (95%) rename docs/user/{five_step_setup/docs.user.five.md => five_day_setup/docs.user.five_day_setup.md} (76%) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 3aa3c9e414..53e5534185 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -3,7 +3,7 @@ "_label": "User Guide", "_toc": [ "docs.user.intro", - "docs.user.five", + "docs.user.five_day_setup", "docs.user.implement", "docs.user.setup", "docs.user.selling", @@ -30,12 +30,12 @@ Contents 1. [Open Source](docs.user.intro.open_source.html) 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) -1. [Five-Day-Setup](docs.user.five.html) - 1. [Day-1](docs.user.five.day_1.html) - 1. [Day-2](docs.user.five.day_2.html) - 1. [Day-3](docs.user.five.day_3.html) - 1. [Day-4](docs.user.five.day_4.html) - 1. [Day-5](docs.user.five.day_5.html) +1. [Five-Day-Setup](docs.user.five_day_setup.html) + 1. [Day-1](docs.user.five_day_setup.day_1.html) + 1. [Day-2](docs.user.five_day_setup.day_2.html) + 1. [Day-3](docs.user.five_day_setup.day_3.html) + 1. [Day-4](docs.user.five_day_setup.day_4.html) + 1. [Day-5](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md similarity index 94% rename from docs/user/five_step_setup/docs.user.five.day_1.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index d6786b40da..34f85dd911 100644 --- a/docs/user/five_step_setup/docs.user.five.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -26,20 +26,20 @@ After filling this form, you will get a pop-up message for completing the set-u The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon. -![Customer](img/firstdaysetup_customer.png) +![Customer](img/firstdaysetup-customer.png)
After clicking on Customer, a new form will appear.
-![Customer](img/firstdaysetup_customer_1.png) +![Customer](img/firstdaysetup-customer-1.png) To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system. Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup -![Main Menu](img/firstdaysetup_main_menu.png) +![Main Menu](img/firstdaysetup-main-menu.png)
@@ -48,7 +48,7 @@ Now proceed to make an Item. To go to the main menu, click on erpnext icon which On the setup page go to Item. -![Item](img/firstdaysetup_item.png) +![Item](img/firstdaysetup-item.png) Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers. diff --git a/docs/user/five_step_setup/docs.user.five.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md similarity index 100% rename from docs/user/five_step_setup/docs.user.five.day_2.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_2.md diff --git a/docs/user/five_step_setup/docs.user.five.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md similarity index 97% rename from docs/user/five_step_setup/docs.user.five.day_3.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index 09a5d3f4ac..dc7acef0fd 100644 --- a/docs/user/five_step_setup/docs.user.five.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -14,7 +14,7 @@ Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. -![Lead](img/thirddaysetup_lead.png) +![Lead](img/thirddaysetup-lead.png) Fill the Lead form. @@ -83,7 +83,7 @@ Save and Submit your Delivery Note to generate a Sales Invoice. You can also gen A Journal Voucher or a payment entry can be generated directly from the Sales Invoice. -![Payment Entry](img/thirddaysetup_payment_entry.png) +![Payment Entry](img/thirddaysetup-payment-entry.png) > To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md similarity index 92% rename from docs/user/five_step_setup/docs.user.five.day_4.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index d23fe54585..f4938e9c07 100644 --- a/docs/user/five_step_setup/docs.user.five.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -33,7 +33,7 @@ To go to Production Planning Tool, click on the Manufacturing Icon. On the Manuf To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. -![Production Order](img/fourthdaysetup_po.png) +![Production Order](img/fourthdaysetup-po.png)
@@ -43,7 +43,7 @@ To go to Production Order click on the Manufacturing Icon. On the Manufacturing To go to Stock Entry, click on the Stock Icon and go to Stock Entry. -![Stock Entry](img/fourthdaysetup_stock.png) +![Stock Entry](img/fourthdaysetup-stock.png)
@@ -69,7 +69,7 @@ To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Not To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. -![Warehouse](img/fourthdaysetup_warehouse.png) +![Warehouse](img/fourthdaysetup-warehouse.png)
@@ -84,7 +84,7 @@ Make a few Journal Vouchers. Generate some Accounting Reports. To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. -![Journal Voucher](img/fourthdaysetup_jv.png) +![Journal Voucher](img/fourthdaysetup-jv.png) > To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md similarity index 95% rename from docs/user/five_step_setup/docs.user.five.day_5.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index 30c64c3708..b69fccd6ed 100644 --- a/docs/user/five_step_setup/docs.user.five.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -14,7 +14,7 @@ Project is divided into Tasks and each Task is allocated to a resource. In ERPNe To create a Task, go to Project and click on Task. -![Tasks](img/fifthdaysetup_task.png) +![Tasks](img/fifthdaysetup-tasks.png)
diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_day_setup/docs.user.five_day_setup.md similarity index 76% rename from docs/user/five_step_setup/docs.user.five.md rename to docs/user/five_day_setup/docs.user.five_day_setup.md index 21170c5988..d296914f9e 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.md @@ -2,18 +2,18 @@ { "_label": "Five-Day Setup", "_toc": [ - "docs.user.five.day_1", - "docs.user.five.day_2", - "docs.user.five.day_3", - "docs.user.five.day_4", - "docs.user.five.day_5" + "docs.user.five_day_setup.day_1", + "docs.user.five_day_setup.day_2", + "docs.user.five_day_setup.day_3", + "docs.user.five_day_setup.day_4", + "docs.user.five_day_setup.day_5" ] } --- Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation. -The setup help is divided into day-wise instructions for 5 consecutive days. Day 1 will cover the following topics: +The setup help is divided into day-wise instructions for 5 consecutive days. #### Day 1 From 77f37e6b7c65586dfab58e31ad55d6f508d65180 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 8 Oct 2013 17:11:33 +0530 Subject: [PATCH 16/43] Update Serial No details through serial_no controller --- .../doctype/sales_invoice/sales_invoice.py | 2 - controllers/selling_controller.py | 32 +-- .../october_2013/p01_fix_serial_no_status.py | 37 +-- ...petual_inventory_stock_transfer_utility.py | 10 +- stock/doctype/delivery_note/delivery_note.py | 31 --- .../landed_cost_wizard/landed_cost_wizard.py | 2 - .../purchase_receipt/purchase_receipt.py | 21 +- stock/doctype/serial_no/serial_no.py | 223 ++++++++++++++++-- stock/doctype/stock_entry/stock_entry.py | 24 +- stock/doctype/stock_entry/test_stock_entry.py | 16 +- .../stock_ledger_entry/stock_ledger_entry.py | 126 +--------- 11 files changed, 250 insertions(+), 274 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 2eb9ae84cb..daf01ab801 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -83,7 +83,6 @@ class DocType(SellingController): def on_submit(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos() else: # Check for Approving Authority if not self.doc.recurring_id: @@ -111,7 +110,6 @@ class DocType(SellingController): def on_cancel(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos(cancel = True) sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index f1117ed177..37674ee4bf 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -233,34 +233,4 @@ class SellingController(StockController): self.doc.order_type = "Sales" elif self.doc.order_type not in valid_types: msgprint(_(self.meta.get_label("order_type")) + " " + - _("must be one of") + ": " + comma_or(valid_types), - raise_exception=True) - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, self.doc.doctype, self.fname) - update_serial_nos_after_submit(self, self.doc.doctype, "packing_details") - - for table_fieldname in (self.fname, "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = self.doc.doctype - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() + _("must be one of") + ": " + comma_or(valid_types), raise_exception=True) \ No newline at end of file diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py index 8700290fcd..38423281a1 100644 --- a/patches/october_2013/p01_fix_serial_no_status.py +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -6,35 +6,12 @@ import webnotes from webnotes.utils import flt def execute(): - serial_nos = webnotes.conn.sql("""select name, item_code, status from `tabSerial No` - where status!='Not in Use'""", as_dict=1) + serial_nos = webnotes.conn.sql("""select name from `tabSerial No` where status!='Not in Use' + and docstatus=0""") for sr in serial_nos: - last_sle = webnotes.conn.sql("""select voucher_type, voucher_no, actual_qty - from `tabStock Ledger Entry` where serial_no like %s and item_code=%s - order by name desc limit 1""", - ("%%%s%%" % sr.name, sr.item_code), as_dict=1) - - if flt(last_sle[0].actual_qty) > 0: - if last_sle[0].voucher_type == "Stock Entry" and webnotes.conn.get_value("Stock Entry", - last_sle[0].voucher_no, "purpose") == "Sales Return": - status = "Sales Returned" - else: - status = "Available" - else: - if last_sle[0].voucher_type == "Stock Entry": - purpose = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, "purpose") - if purpose == "Purchase Return": - status = "Purchase Returned" - else: - status = "Not Available" - else: - status = "Delivered" - if sr.status != status: - webnotes.conn.sql("""update `tabSerial No` set status=%s where name=%s""", - (status, sr.name)) + sr_bean = webnotes.bean("Serial No", sr[0]) + sr_bean.make_controller().via_stock_ledger = True + sr_bean.save() - webnotes.conn.sql("""update `tabSerial No` set warehouse='' - where status in ('Delivered', 'Purchase Returned')""") - - - \ No newline at end of file + webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in + ('Delivered', 'Purchase Returned')""") \ No newline at end of file diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index 8cee29a824..d8cade78eb 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -29,9 +29,10 @@ def execute(): cost_center = "Default CC Ledger - NISL" for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!='' - and ifnull(warehouse, '')!='' and ifnull(actual_qty, 0) != 0 - and (select company from tabWarehouse where name=bin.warehouse)=%s""", - company[0], as_dict=1): + and ifnull(warehouse, '') in (%s) and ifnull(actual_qty, 0) != 0 + and (select company from tabWarehouse where name=bin.warehouse)=%s""" % + (', '.join(['%s']*len(warehouse_map)), '%s'), + (warehouse_map.keys() + [company[0]]), as_dict=1): item_details = item_map[bin.item_code] new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ if cstr(item_details.is_asset_item) == "Yes" \ @@ -40,7 +41,8 @@ def execute(): if item_details.has_serial_no == "Yes": serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name from `tabSerial No` where item_code = %s and warehouse = %s - and status='Available'""", (bin.item_code, bin.warehouse))]) + and status in ('Available', 'Sales Returned')""", + (bin.item_code, bin.warehouse))]) else: serial_no = None diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index e5e412e44b..2d1a3bece6 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -185,7 +185,6 @@ class DocType(SellingController): # create stock ledger entry self.update_stock_ledger() - self.update_serial_nos() self.credit_limit() @@ -203,42 +202,12 @@ class DocType(SellingController): self.update_prevdoc_status() self.update_stock_ledger() - self.update_serial_nos(cancel=True) webnotes.conn.set(self.doc, 'status', 'Cancelled') self.cancel_packing_slips() self.make_cancel_gl_entries() - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Delivery Note", "delivery_note_details") - update_serial_nos_after_submit(self, "Delivery Note", "packing_details") - - for table_fieldname in ("delivery_note_details", "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = "Delivery Note" - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() - def validate_packed_qty(self): """ Validate that if packed qty exists, it should be equal to qty diff --git a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py index 0924957338..89a3b81d57 100644 --- a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py +++ b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py @@ -85,7 +85,6 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty", is_cancelled="Yes") - pr_bean.run_method("update_serial_nos", cancel=True) webnotes.conn.sql("""delete from `tabStock Ledger Entry` where voucher_type='Purchase Receipt' and voucher_no=%s""", pr) @@ -97,5 +96,4 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty") pr_bean.run_method("update_stock") - pr_bean.run_method("update_serial_nos") pr_bean.run_method("make_gl_entries") \ No newline at end of file diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 7d663b8778..6169b1d916 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -246,26 +246,12 @@ class DocType(BuyingController): self.update_stock() - self.update_serial_nos() + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") purchase_controller.update_last_purchase_rate(self, 1) self.make_gl_entries() - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") - - for d in self.doclist.get({"parentfield": "purchase_receipt_details"}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.supplier = None - sr.doc.supplier_name = None - else: - sr.doc.supplier = self.doc.supplier - sr.doc.supplier_name = self.doc.supplier_name - sr.save() def check_next_docstatus(self): submit_rv = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % (self.doc.name)) @@ -292,7 +278,6 @@ class DocType(BuyingController): self.update_ordered_qty() self.update_stock() - self.update_serial_nos(cancel=True) self.update_prevdoc_status() pc_obj.update_last_purchase_rate(self, 0) @@ -308,7 +293,7 @@ class DocType(BuyingController): def get_rate(self,arg): return get_obj('Purchase Common').get_rate(arg,self) - + def get_gl_entries_for_stock(self, warehouse_account=None): against_stock_account = self.get_company_default("stock_received_but_not_billed") diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 1feab02cf5..c8b7222033 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -4,14 +4,22 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, getdate, nowdate +from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days import datetime -from webnotes import msgprint, _ +from webnotes import msgprint, _, ValidationError from controllers.stock_controller import StockController -class SerialNoCannotCreateDirectError(webnotes.ValidationError): pass -class SerialNoCannotCannotChangeError(webnotes.ValidationError): pass +class SerialNoCannotCreateDirectError(ValidationError): pass +class SerialNoCannotCannotChangeError(ValidationError): pass +class SerialNoNotRequiredError(ValidationError): pass +class SerialNoRequiredError(ValidationError): pass +class SerialNoQtyError(ValidationError): pass +class SerialNoItemError(ValidationError): pass +class SerialNoWarehouseError(ValidationError): pass +class SerialNoStatusError(ValidationError): pass +class SerialNoNotExistsError(ValidationError): pass +class SerialNoDuplicateError(ValidationError): pass class DocType(StockController): def __init__(self, doc, doclist=[]): @@ -21,13 +29,18 @@ class DocType(StockController): def validate(self): if self.doc.fields.get("__islocal") and self.doc.warehouse: - webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), - SerialNoCannotCreateDirectError) + webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be \ + set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError) self.validate_warranty_status() self.validate_amc_status() self.validate_warehouse() self.validate_item() + + if self.via_stock_ledger: + self.set_status() + self.set_purchase_details() + self.set_sales_details() def validate_amc_status(self): """ @@ -41,7 +54,8 @@ class DocType(StockController): validate warranty status """ if (self.doc.maintenance_status == 'Out of Warranty' and self.doc.warranty_expiry_date and getdate(self.doc.warranty_expiry_date) >= datetime.date.today()) or (self.doc.maintenance_status == 'Under Warranty' and (not self.doc.warranty_expiry_date or getdate(self.doc.warranty_expiry_date) < datetime.date.today())): - msgprint("Warranty expiry date and maintenance status mismatch. Please verify", raise_exception=1) + msgprint("Warranty expiry date and maintenance status mismatch. Please verify", + raise_exception=1) def validate_warehouse(self): @@ -49,10 +63,11 @@ class DocType(StockController): item_code, warehouse = webnotes.conn.get_value("Serial No", self.doc.name, ["item_code", "warehouse"]) if item_code != self.doc.item_code: - webnotes.throw(_("Item Code cannot be changed for Serial No."), SerialNoCannotCannotChangeError) + webnotes.throw(_("Item Code cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) if not self.via_stock_ledger and warehouse != self.doc.warehouse: - webnotes.throw(_("Warehouse cannot be changed for Serial No."), SerialNoCannotCannotChangeError) - + webnotes.throw(_("Warehouse cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) def validate_item(self): """ @@ -67,16 +82,89 @@ class DocType(StockController): self.doc.item_name = item.item_name self.doc.brand = item.brand self.doc.warranty_period = item.warranty_period + + def set_status(self): + last_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and ifnull(is_cancelled, 'No')='No' + order by name desc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + + if last_sle: + if last_sle[0].voucher_type == "Stock Entry": + document_type = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, + "purpose") + else: + document_type = last_sle[0].voucher_type + + if last_sle[0].actual_qty > 0: + if document_type == "Sales Return": + self.doc.status = "Sales Returned" + else: + self.doc.status = "Available" + else: + if document_type == "Purchase Return": + self.doc.status = "Purchase Returned" + elif last_sle[0].voucher_type in ("Delivery Note", "Sales Invoice"): + self.doc.status = "Delivered" + else: + self.doc.status = "Not Available" + + def set_purchase_details(self): + purchase_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty > 0 + and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + if purchase_sle: + self.doc.purchase_document_type = purchase_sle[0].voucher_type + self.doc.purchase_document_no = purchase_sle[0].voucher_no + self.doc.purchase_date = purchase_sle[0].posting_date + self.doc.purchase_time = purchase_sle[0].posting_time + self.doc.purchase_rate = purchase_sle[0].incoming_rate + if purchase_sle[0].voucher_type == "Purchase Receipt": + self.doc.supplier, self.doc.supplier_name = \ + webnotes.conn.get_value("Purchase Receipt", purchase_sle[0].voucher_no, + ["supplier_name", "supplier_name"]) + else: + for fieldname in ("purchase_document_type", "purchase_document_no", + "purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"): + self.doc.fields[fieldname] = None + + def set_sales_details(self): + delivery_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty<0 + and voucher_type in ('Delivery Note', 'Sales Invoice') + and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + if delivery_sle: + self.doc.delivery_document_type = delivery_sle[0].voucher_type + self.doc.delivery_document_no = delivery_sle[0].voucher_no + self.doc.delivery_date = delivery_sle[0].posting_date + self.doc.delivery_time = delivery_sle[0].posting_time + self.doc.customer, self.doc.customer_name = \ + webnotes.conn.get_value(delivery_sle[0].voucher_type, delivery_sle[0].voucher_no, + ["customer", "customer_name"]) + if self.doc.warranty_period: + self.doc.warranty_expiry_date = add_days(cstr(delivery_sle[0].posting_date), + cint(self.doc.warranty_period)) + else: + for fieldname in ("delivery_document_type", "delivery_document_no", + "delivery_date", "delivery_time", "customer", "customer_name", + "warranty_expiry_date"): + self.doc.fields[fieldname] = None + def on_trash(self): if self.doc.status == 'Delivered': - msgprint("Cannot trash Serial No : %s as it is already Delivered" % (self.doc.name), raise_exception = 1) + webnotes.throw(_("Delivered Serial No ") + self.doc.name + _(" can not be deleted")) if self.doc.warehouse: - webnotes.throw(_("Cannot delete Serial No in warehouse. First remove from warehouse, then delete.") + \ - ": " + self.doc.name) - - def on_cancel(self): - self.on_trash() + webnotes.throw(_("Cannot delete Serial No in warehouse. \ + First remove from warehouse, then delete.") + ": " + self.doc.name) def on_rename(self, new, old, merge=False): """rename serial_no text fields""" @@ -93,3 +181,106 @@ class DocType(StockController): webnotes.conn.sql("""update `tab%s` set serial_no = %s where name=%s""" % (dt[0], '%s', '%s'), ('\n'.join(serial_nos), item[0])) + +def process_serial_no(sle): + item_det = get_item_details(sle.item_code) + validate_serial_no(sle, item_det) + update_serial_nos(sle, item_det) + +def validate_serial_no(sle, item_det): + if item_det.has_serial_no=="No": + if sle.serial_no: + webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + + sle.item_code), SerialNoNotRequiredError) + else: + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + if cint(sle.actual_qty) != flt(sle.actual_qty): + webnotes.throw(_("Serial No qty cannot be a fraction") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty))) + if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)): + webnotes.throw(_("Serial Nos do not match with qty") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty)), SerialNoQtyError) + + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + + if sr.doc.item_code!=sle.item_code: + webnotes.throw(_("Serial No does not belong to Item") + + (": %s (%s)" % (sle.item_code, serial_no)), SerialNoItemError) + + if sr.doc.warehouse and sle.actual_qty > 0: + webnotes.throw(_("Same Serial No") + ": " + sr.doc.name + + _(" can not be received twice"), SerialNoDuplicateError) + + if sle.actual_qty < 0: + if sr.doc.warehouse!=sle.warehouse: + webnotes.throw(_("Serial No") + ": " + serial_no + + _(" does not belong to Warehouse") + ": " + sle.warehouse, + SerialNoWarehouseError) + + if sle.voucher_type in ("Delivery Note", "Sales Invoice") \ + and sr.doc.status != "Available": + webnotes.throw(_("Serial No status must be 'Available' to Deliver") + + ": " + serial_no, SerialNoStatusError) + elif sle.actual_qty < 0: + # transfer out + webnotes.throw(_("Serial No must exist to transfer out.") + \ + ": " + serial_no, SerialNoNotExistsError) + elif not item_det.serial_no_series: + webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + + sle.item_code), SerialNoRequiredError) + +def update_serial_nos(sle, item_det): + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + sr.make_controller().via_stock_ledger = True + sr.doc.warehouse = sle.warehouse if sle.actual_qty > 0 else None + sr.save() + elif sle.actual_qty > 0: + make_serial_no(serial_no, sle) + elif sle.actual_qty > 0 and item_det.serial_no_series: + from webnotes.model.doc import make_autoname + serial_nos = [] + for i in xrange(cint(sle.actual_qty)): + serial_nos.append(make_serial_no(make_autoname(item_det.serial_no_series), sle)) + sle.serial_no = "\n".join(serial_nos) + +def get_item_details(item_code): + return webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", item_code, as_dict=True)[0] + +def get_serial_nos(serial_no): + return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] + +def make_serial_no(serial_no, sle): + sr = webnotes.new_bean("Serial No") + sr.doc.serial_no = serial_no + sr.doc.item_code = sle.item_code + sr.make_controller().via_stock_ledger = True + sr.insert() + sr.doc.warehouse = sle.warehouse + sr.doc.status = "Available" + sr.save() + webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) + return sr.doc.name + +def update_serial_nos_after_submit(controller, parenttype, parentfield): + if not hasattr(webnotes, "new_stock_ledger_entries"): + return + + for d in controller.doclist.get({"parentfield": parentfield}): + serial_no = None + for sle in webnotes.new_stock_ledger_entries: + if sle.voucher_detail_no==d.name: + serial_no = sle.serial_no + break + + if d.serial_no != serial_no: + d.serial_no = serial_no + webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) \ 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 a54f9bf05b..8d2e76490c 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -52,13 +52,15 @@ class DocType(StockController): def on_submit(self): self.update_stock_ledger() - self.update_serial_no(1) + + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") + self.update_production_order(1) self.make_gl_entries() def on_cancel(self): self.update_stock_ledger() - self.update_serial_no(0) self.update_production_order(0) self.make_cancel_gl_entries() @@ -294,24 +296,6 @@ class DocType(StockController): from `tabStock Entry Detail` where parent in ( select name from `tabStock Entry` where `%s`=%s and docstatus=1) group by item_code""" % (ref_fieldname, "%s"), (self.doc.fields.get(ref_fieldname),))) - - def update_serial_no(self, is_submit): - """Create / Update Serial No""" - - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") - - for d in getlist(self.doclist, 'mtn_details'): - for serial_no in get_serial_nos(d.serial_no): - if self.doc.purpose == 'Purchase Return': - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Purchase Returned" if is_submit else "Available" - sr.save() - - if self.doc.purpose == "Sales Return": - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Sales Returned" if is_submit else "Delivered" - sr.save() def update_stock_ledger(self): sl_entries = [] diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index e2358eba4f..b41a6269ad 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import webnotes, unittest from webnotes.utils import flt -from stock.doctype.stock_ledger_entry.stock_ledger_entry import * +from stock.doctype.serial_no.serial_no import * from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory @@ -48,7 +48,7 @@ class TestStockEntry(unittest.TestCase): webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - from stock.doctype.stock_ledger_entry.stock_ledger_entry import InvalidWarehouseCompany + from stock.utils import InvalidWarehouseCompany st1 = webnotes.bean(copy=test_records[0]) st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() @@ -721,6 +721,18 @@ class TestStockEntry(unittest.TestCase): se.insert() self.assertRaises(SerialNoNotExistsError, se.submit) + def test_serial_duplicate(self): + self._clear_stock_account_balance() + self.test_serial_by_series() + + se = webnotes.bean(copy=test_records[0]) + se.doclist[1].item_code = "_Test Serialized Item With Series" + se.doclist[1].qty = 1 + se.doclist[1].serial_no = "ABCD00001" + se.doclist[1].transfer_qty = 1 + se.insert() + self.assertRaises(SerialNoDuplicateError, se.submit) + def test_serial_by_series(self): self._clear_stock_account_balance() se = make_serialized_item() diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 6fea546ba6..8fef889f72 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -3,21 +3,10 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint, ValidationError +from webnotes import _, msgprint from webnotes.utils import cint, flt, getdate, cstr from webnotes.model.controller import DocListController -class SerialNoNotRequiredError(ValidationError): pass -class SerialNoRequiredError(ValidationError): pass -class SerialNoQtyError(ValidationError): pass -class SerialNoItemError(ValidationError): pass -class SerialNoWarehouseError(ValidationError): pass -class SerialNoStatusError(ValidationError): pass -class SerialNoNotExistsError(ValidationError): pass - -def get_serial_nos(serial_no): - return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] - class DocType(DocListController): def __init__(self, doc, doclist=[]): self.doc = doc @@ -41,7 +30,9 @@ class DocType(DocListController): def on_submit(self): self.check_stock_frozen_date() self.actual_amt_check() - self.validate_serial_no() + + from stock.doctype.serial_no.serial_no import process_serial_no + process_serial_no(self.doc) #check for item quantity available in stock def actual_amt_check(self): @@ -73,7 +64,10 @@ class DocType(DocListController): msgprint("Warehouse: '%s' does not exist in the system. Please check." % self.doc.fields.get(k), raise_exception = 1) def validate_item(self): - item_det = self.get_item_details() + item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", + self.doc.item_code, as_dict=True)[0] if item_det.is_stock_item != 'Yes': webnotes.throw("""Item: "%s" is not a Stock Item.""" % self.doc.item_code) @@ -91,95 +85,6 @@ class DocType(DocListController): if not self.doc.stock_uom: self.doc.stock_uom = item_det.stock_uom - def get_item_details(self): - return webnotes.conn.sql("""select name, has_batch_no, docstatus, - is_stock_item, has_serial_no, serial_no_series - from tabItem where name=%s""", - self.doc.item_code, as_dict=True)[0] - - def validate_serial_no(self): - item_det = self.get_item_details() - - if item_det.has_serial_no=="No": - if self.doc.serial_no: - webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + self.doc.item), - SerialNoNotRequiredError) - else: - if self.doc.serial_no: - serial_nos = get_serial_nos(self.doc.serial_no) - if cint(self.doc.actual_qty) != flt(self.doc.actual_qty): - webnotes.throw(_("Serial No qty cannot be a fraction") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty))) - if len(serial_nos) and len(serial_nos) != abs(cint(self.doc.actual_qty)): - webnotes.throw(_("Serial Nos do not match with qty") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty)), SerialNoQtyError) - - # check serial no exists, if yes then source - for serial_no in serial_nos: - if webnotes.conn.exists("Serial No", serial_no): - sr = webnotes.bean("Serial No", serial_no) - - if sr.doc.item_code!=self.doc.item_code: - webnotes.throw(_("Serial No does not belong to Item") + \ - (": %s (%s)" % (self.doc.item_code, serial_no)), SerialNoItemError) - - sr.make_controller().via_stock_ledger = True - - if self.doc.actual_qty < 0: - if sr.doc.warehouse!=self.doc.warehouse: - webnotes.throw(_("Serial No") + ": " + serial_no + - _(" does not belong to Warehouse") + ": " + self.doc.warehouse, - SerialNoWarehouseError) - - if self.doc.voucher_type in ("Delivery Note", "Sales Invoice") \ - and sr.doc.status != "Available": - webnotes.throw(_("Serial No status must be 'Available' to Deliver") - + ": " + serial_no, SerialNoStatusError) - - - sr.doc.warehouse = None - sr.save() - else: - sr.doc.warehouse = self.doc.warehouse - sr.save() - else: - if self.doc.actual_qty < 0: - # transfer out - webnotes.throw(_("Serial No must exist to transfer out.") + \ - ": " + serial_no, SerialNoNotExistsError) - else: - # transfer in - self.make_serial_no(serial_no) - else: - if item_det.serial_no_series: - from webnotes.model.doc import make_autoname - serial_nos = [] - for i in xrange(cint(self.doc.actual_qty)): - serial_nos.append(self.make_serial_no(make_autoname(item_det.serial_no_series))) - self.doc.serial_no = "\n".join(serial_nos) - else: - webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item_code), - SerialNoRequiredError) - - def make_serial_no(self, serial_no): - sr = webnotes.new_bean("Serial No") - sr.doc.serial_no = serial_no - sr.doc.item_code = self.doc.item_code - sr.doc.purchase_rate = self.doc.incoming_rate - sr.doc.purchase_document_type = self.doc.voucher_type - sr.doc.purchase_document_no = self.doc.voucher_no - sr.doc.purchase_date = self.doc.posting_date - sr.doc.purchase_time = self.doc.posting_time - sr.make_controller().via_stock_ledger = True - sr.insert() - - # set warehouse - sr.doc.warehouse = self.doc.warehouse - sr.doc.status = "Available" - sr.save() - webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) - return sr.doc.name - def check_stock_frozen_date(self): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: @@ -191,21 +96,6 @@ class DocType(DocListController): if not self.doc.posting_time or self.doc.posting_time == '00:0': self.doc.posting_time = '00:00' -def update_serial_nos_after_submit(controller, parenttype, parentfield): - if not hasattr(webnotes, "new_stock_ledger_entries"): - return - - for d in controller.doclist.get({"parentfield": parentfield}): - serial_no = None - for sle in webnotes.new_stock_ledger_entries: - if sle.voucher_detail_no==d.name: - serial_no = sle.serial_no - break - - if d.serial_no != serial_no: - d.serial_no = serial_no - webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) - def on_doctype_update(): if not webnotes.conn.sql("""show index from `tabStock Ledger Entry` where Key_name="posting_sort_index" """): From 609046990b5544a6e5596780d162afcc80281ae7 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 8 Oct 2013 17:58:41 +0530 Subject: [PATCH 17/43] [fix] [minor] fix in serial no --- patches/october_2013/p01_fix_serial_no_status.py | 1 + stock/doctype/serial_no/serial_no.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py index 38423281a1..0bfc400a8e 100644 --- a/patches/october_2013/p01_fix_serial_no_status.py +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -11,6 +11,7 @@ def execute(): for sr in serial_nos: sr_bean = webnotes.bean("Serial No", sr[0]) sr_bean.make_controller().via_stock_ledger = True + sr_bean.run_method("validate") sr_bean.save() webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index c8b7222033..3922878280 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -88,7 +88,7 @@ class DocType(StockController): where (serial_no like %s or serial_no like %s or serial_no=%s) and item_code=%s and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) if last_sle: @@ -116,9 +116,9 @@ class DocType(StockController): where (serial_no like %s or serial_no like %s or serial_no=%s) and item_code=%s and actual_qty > 0 and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) - + if purchase_sle: self.doc.purchase_document_type = purchase_sle[0].voucher_type self.doc.purchase_document_no = purchase_sle[0].voucher_no @@ -128,7 +128,7 @@ class DocType(StockController): if purchase_sle[0].voucher_type == "Purchase Receipt": self.doc.supplier, self.doc.supplier_name = \ webnotes.conn.get_value("Purchase Receipt", purchase_sle[0].voucher_no, - ["supplier_name", "supplier_name"]) + ["supplier", "supplier_name"]) else: for fieldname in ("purchase_document_type", "purchase_document_no", "purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"): @@ -140,7 +140,7 @@ class DocType(StockController): and item_code=%s and actual_qty<0 and voucher_type in ('Delivery Note', 'Sales Invoice') and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) if delivery_sle: self.doc.delivery_document_type = delivery_sle[0].voucher_type From 94a9a479fedb4ef4986a60c71b5034529e341c72 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 11:16:08 +0530 Subject: [PATCH 18/43] [report] supplier addresses and contacts --- buying/page/buying_home/buying_home.js | 5 +++++ .../__init__.py | 0 .../supplier_addresses_and_contacts.txt | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 buying/report/supplier_addresses_and_contacts/__init__.py create mode 100644 buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js index 5db57f4f02..eec0725de9 100644 --- a/buying/page/buying_home/buying_home.js +++ b/buying/page/buying_home/buying_home.js @@ -145,6 +145,11 @@ wn.module_page["Buying"] = [ route: "query-report/Purchase Order Trends", doctype: "Purchase Order" }, + { + "label":wn._("Supplier Addresses And Contacts"), + route: "query-report/Supplier Addresses and Contacts", + doctype: "Supplier" + }, ] } ] diff --git a/buying/report/supplier_addresses_and_contacts/__init__.py b/buying/report/supplier_addresses_and_contacts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt new file mode 100644 index 0000000000..fac1e9e929 --- /dev/null +++ b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-10-09 10:38:40", + "docstatus": 0, + "modified": "2013-10-09 10:53:52", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc", + "ref_doctype": "Supplier", + "report_name": "Supplier Addresses and Contacts", + "report_type": "Query Report" + }, + { + "doctype": "Report", + "name": "Supplier Addresses and Contacts" + } +] \ No newline at end of file From 6ec7d9d3f95920dfc70b0a6c92697d1fa1bfe4a9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 11:46:50 +0530 Subject: [PATCH 19/43] [fix] [minor] item-wose tax in item-wise sales register --- .../item_wise_purchase_register.py | 4 ++-- .../item_wise_sales_register.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index bd0726e37d..1c3cef3115 100644 --- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -81,12 +81,12 @@ def get_tax_accounts(item_list, columns): if account_head not in tax_accounts: tax_accounts.append(account_head) - invoice = item_tax.setdefault(parent, {}) if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 77fb6f25e6..48bc463f14 100644 --- a/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -9,7 +9,7 @@ def execute(filters=None): if not filters: filters = {} columns = get_columns() last_col = len(columns) - + item_list = get_items(filters) item_tax, tax_accounts = get_tax_accounts(item_list, columns) @@ -21,7 +21,7 @@ def execute(filters=None): for tax in tax_accounts: row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0)) - + total_tax = sum(row[last_col:]) row += [total_tax, d.amount + total_tax] @@ -71,19 +71,19 @@ def get_tax_accounts(item_list, columns): tax_details = webnotes.conn.sql("""select parent, account_head, item_wise_tax_detail from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' and docstatus = 1 and ifnull(account_head, '') != '' - and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list])) + and parent in (%s)""" % ', '.join(['%s']*len(item_list)), + tuple([item.parent for item in item_list])) for parent, account_head, item_wise_tax_detail in tax_details: if account_head not in tax_accounts: tax_accounts.append(account_head) - - invoice = item_tax.setdefault(parent, {}) + if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) - + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue From 3235e787c4b32e243a6da97736f60a6d36a0f47c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 12:04:41 +0530 Subject: [PATCH 20/43] [fix] [minor] Pick cost_center from tax table for expense included in valuation --- .../purchase_invoice/purchase_invoice.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 7e19fb3ef9..3c3bcb7022 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -335,7 +335,7 @@ class DocType(BuyingController): ) # tax table gl entries - valuation_tax = 0 + valuation_tax = {} for tax in self.doclist.get({"parentfield": "purchase_tax_details"}): if tax.category in ("Total", "Valuation and Total") and flt(tax.tax_amount): gl_entries.append( @@ -350,8 +350,11 @@ class DocType(BuyingController): ) # accumulate valuation tax - if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount): - valuation_tax += (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) + if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount) \ + and tax.cost_center: + valuation_tax.setdefault(tax.cost_center, 0) + valuation_tax[tax.cost_center] += \ + (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) # item gl entries stock_item_and_auto_accounting_for_stock = False @@ -392,15 +395,19 @@ class DocType(BuyingController): if stock_item_and_auto_accounting_for_stock and valuation_tax: # credit valuation tax amount in "Expenses Included In Valuation" # this will balance out valuation amount included in cost of goods sold - gl_entries.append( - self.get_gl_dict({ - "account": self.get_company_default("expenses_included_in_valuation"), - "cost_center": self.get_company_default("cost_center"), - "against": self.doc.credit_to, - "credit": valuation_tax, - "remarks": self.doc.remarks or "Accounting Entry for Stock" - }) - ) + expenses_included_in_valuation = \ + self.get_company_default("expenses_included_in_valuation") + + for cost_center, amount in valuation_tax.items(): + gl_entries.append( + self.get_gl_dict({ + "account": expenses_included_in_valuation, + "cost_center": cost_center, + "against": self.doc.credit_to, + "credit": amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock" + }) + ) # writeoff account includes petty difference in the invoice amount # and the amount that is paid From 13bed4ef85f394b2c2012b35e7896e4c705f5d97 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 12:24:31 +0530 Subject: [PATCH 21/43] [fix] [minor] manitenance schedules report --- .../report/maintenance_schedules/maintenance_schedules.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/support/report/maintenance_schedules/maintenance_schedules.txt b/support/report/maintenance_schedules/maintenance_schedules.txt index 525f4834ba..766eb20151 100644 --- a/support/report/maintenance_schedules/maintenance_schedules.txt +++ b/support/report/maintenance_schedules/maintenance_schedules.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-06 14:25:21", "docstatus": 0, - "modified": "2013-05-06 14:32:47", + "modified": "2013-10-09 12:23:27", "modified_by": "Administrator", "owner": "Administrator" }, @@ -10,7 +10,7 @@ "doctype": "Report", "is_standard": "Yes", "name": "__common__", - "query": "SELECT\n ms_item.scheduled_date as \"Schedule Date:Date:120\",\n\tms_item.item_code as \"Item Code:Link/Item:120\",\n\tms_item.item_name as \"Item Name::120\",\n\tms_item.serial_no as \"Serial No::120\",\n\tms_item.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms.sales_order_no as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, `tabMaintenance Schedule Detail` ms_item\nWHERE\n\tms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_item.scheduled_date asc, ms_item.item_code asc", + "query": "SELECT\n ms_sch.scheduled_date as \"Schedule Date:Date:120\",\n\tms_sch.item_code as \"Item Code:Link/Item:120\",\n\tms_sch.item_name as \"Item Name::120\",\n\tms_sch.serial_no as \"Serial No::120\",\n\tms_sch.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms_item.prevdoc_docname as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, \n `tabMaintenance Schedule Detail` ms_sch, \n `tabMaintenance Schedule Item` ms_item\nWHERE\n\tms.name = ms_sch.parent and ms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_sch.scheduled_date asc, ms_sch.item_code asc", "ref_doctype": "Maintenance Schedule", "report_name": "Maintenance Schedules", "report_type": "Query Report" From 11faa57233f113d7123de17c6078271766265d95 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 13:21:36 +0530 Subject: [PATCH 22/43] [fix] [minor] fetching lead details in opportunity --- selling/doctype/lead/lead.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index 316481cbaa..41387f4938 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -133,4 +133,4 @@ def make_opportunity(source_name, target_doclist=None): } }}, target_doclist) - return [d.fields for d in doclist] \ No newline at end of file + return [d if isinstance(d, dict) else d.fields for d in doclist] \ No newline at end of file From 17c8b940e3ab44cafb311992f1d8788f745763e5 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 14:52:18 +0530 Subject: [PATCH 23/43] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 13 ++++--------- selling/doctype/quotation/quotation.py | 16 +--------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index c8c41e3f39..dfb124b448 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -70,10 +70,6 @@ class DocType(TransactionBase): return ret def on_update(self): - # Add to calendar - if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date: - webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date) - self.add_calendar_event() def add_calendar_event(self, opts=None, force=False): @@ -102,12 +98,11 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) def set_last_contact_date(self): - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref + if self.doc.contact_date: + if not self.doc.last_contact_date or (getdate(self.doc.last_contact_date) <= getdate(self.doc.contact_date)): + self.doc.last_contact_date = self.doc.contact_date else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception + webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) def validate_item_details(self): if not getlist(self.doclist, 'enquiry_details'): diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 44a67fa45c..8eb3654e62 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate +from webnotes.utils import cstr from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint @@ -93,19 +93,6 @@ class DocType(SellingController): msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation") raise Exception - #--------------Validation For Last Contact Date----------------- - # ==================================================================================================================== - def set_last_contact_date(self): - #if not self.doc.contact_date_ref: - #self.doc.contact_date_ref=self.doc.contact_date - #self.doc.last_contact_date=self.doc.contact_date_ref - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref - else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception - def validate(self): super(DocType, self).validate() @@ -116,7 +103,6 @@ class DocType(SellingController): utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Order Confirmed", "Order Lost", "Cancelled"]) - self.set_last_contact_date() self.validate_order_type() self.validate_for_items() From 3d72addae03b5010942eceff761f688a9a221613 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:01:17 +0530 Subject: [PATCH 24/43] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index dfb124b448..eaabd0836d 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -98,9 +98,9 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) def set_last_contact_date(self): - if self.doc.contact_date: - if not self.doc.last_contact_date or (getdate(self.doc.last_contact_date) <= getdate(self.doc.contact_date)): - self.doc.last_contact_date = self.doc.contact_date + if self._prev.contact_date: + if not self.doc.last_contact_date or (getdate(self._prev.contact_date) <= getdate(self.doc.contact_date)): + self.doc.last_contact_date = self._prev.contact_date else: webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) From 599fe0532a42a2fd458154aac510139e24025498 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:16:54 +0530 Subject: [PATCH 25/43] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index eaabd0836d..477521ca92 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -18,13 +18,6 @@ class DocType(TransactionBase): self.doclist = doclist self.fname = 'enq_details' self.tname = 'Opportunity Item' - - self._prev = webnotes._dict({ - "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - }) def get_item_details(self, item_code): item = sql("""select item_name, stock_uom, description_html, description, item_group, brand @@ -99,9 +92,9 @@ class DocType(TransactionBase): def set_last_contact_date(self): if self._prev.contact_date: - if not self.doc.last_contact_date or (getdate(self._prev.contact_date) <= getdate(self.doc.contact_date)): + if getdate(self._prev.contact_date) < getdate(self.doc.contact_date): self.doc.last_contact_date = self._prev.contact_date - else: + elif getdate(self._prev.contact_date) > getdate(self.doc.contact_date): webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) def validate_item_details(self): @@ -116,6 +109,13 @@ class DocType(TransactionBase): msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) def validate(self): + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") From 650cfc043489e1a21fadb94424d69e577214ac92 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:26:53 +0530 Subject: [PATCH 26/43] [minor] removed last_contact_date in opportunity --- selling/doctype/opportunity/opportunity.py | 24 +++++++-------------- selling/doctype/opportunity/opportunity.txt | 16 +------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index 477521ca92..5854758b5b 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate, cint +from webnotes.utils import cstr, cint from webnotes.model.bean import getlist from webnotes import msgprint @@ -19,6 +19,13 @@ class DocType(TransactionBase): self.fname = 'enq_details' self.tname = 'Opportunity Item' + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + def get_item_details(self, item_code): item = sql("""select item_name, stock_uom, description_html, description, item_group, brand from `tabItem` where name = %s""", item_code, as_dict=1) @@ -90,13 +97,6 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) - def set_last_contact_date(self): - if self._prev.contact_date: - if getdate(self._prev.contact_date) < getdate(self.doc.contact_date): - self.doc.last_contact_date = self._prev.contact_date - elif getdate(self._prev.contact_date) > getdate(self.doc.contact_date): - webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) - def validate_item_details(self): if not getlist(self.doclist, 'enquiry_details'): msgprint("Please select items for which enquiry needs to be made") @@ -109,14 +109,6 @@ class DocType(TransactionBase): msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) def validate(self): - self._prev = webnotes._dict({ - "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - }) - - self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") self.validate_lead_cust() diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index aeedd08bb8..8a68a31e79 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-09-25 19:32:29", + "modified": "2013-10-09 15:26:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -408,20 +408,6 @@ "oldfieldtype": "Date", "read_only": 0 }, - { - "allow_on_submit": 0, - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "to_discuss", From a0ecfba5f53d280291c9a25fb5fbbd89aca6e366 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:28:16 +0530 Subject: [PATCH 27/43] [minor] removed last_contact_date from lead --- selling/doctype/lead/lead.txt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index 408ad45125..b969906085 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-09-26 16:30:36", + "modified": "2013-10-09 15:27:54", "modified_by": "Administrator", "owner": "Administrator" }, @@ -174,19 +174,6 @@ "options": "Profile", "search_index": 1 }, - { - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "col_break123", From 30bd908833252c65eb3f831998fae04559c671b2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 17:37:41 +0530 Subject: [PATCH 28/43] [fix] [minor] setup leave approver select option in employee --- hr/doctype/employee/employee.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js index 01200e7d22..615e2761b8 100644 --- a/hr/doctype/employee/employee.js +++ b/hr/doctype/employee/employee.js @@ -4,7 +4,6 @@ wn.provide("erpnext.hr"); erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ setup: function() { - this.setup_leave_approver_select(); this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) { return { query:"core.doctype.profile.profile.profile_query"} } this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) { @@ -12,6 +11,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ }, onload: function() { + this.setup_leave_approver_select(); this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"], wn.control_panel.country==="India"); if(this.frm.doc.__islocal) this.frm.set_value("employee_name", ""); From 51f4ac15925107b678982d88f7b8dcf9469a94e8 Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 10 Oct 2013 12:44:31 +0530 Subject: [PATCH 29/43] [docs] minor image changes --- .../five_day_setup/docs.user.five_day_setup.day_1.md | 10 +++++----- .../five_day_setup/docs.user.five_day_setup.day_2.md | 10 +++++----- .../five_day_setup/docs.user.five_day_setup.day_3.md | 12 ++++++------ .../five_day_setup/docs.user.five_day_setup.day_4.md | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index 34f85dd911..a64f833bd7 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -9,7 +9,7 @@ After logging into your account you will receive a pop-up form to fill. Please f #### Form Part I -![1st Form](img/firstdaysetup_1.png) +![1st Form](img/firstdaysetup-1.png)
#### Form Part II
@@ -17,7 +17,7 @@ After logging into your account you will receive a pop-up form to fill. Please f To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) -![1st Form](img/firstdaysetup_2.png) +![1st Form](img/firstdaysetup-2.png) After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear. @@ -55,7 +55,7 @@ Create a new Item. An Item is your company's product or a service.The term Item Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item. -![Item](img/firstdaysetup_item_1.png) +![Item](img/firstdaysetup-item-1.png) To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers. @@ -65,12 +65,12 @@ To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.h On the Setup page go to Supplier. -![Supplier](img/firstdaysetup_supplier.png) +![Supplier](img/firstdaysetup-supplier.png)
Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record. -![Supplier](img/firstdaysetup_supplier_1.png) +![Supplier](img/firstdaysetup-supplier-1.png) To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html). diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index c1a5d28cb7..11e13e2ea9 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -8,14 +8,14 @@ Go to the Accounts icon and make ledgers under Chart of Accounts. -![Accounts](img/seconddaysetup_accounts.png) +![Accounts](img/seconddaysetup-accounts.png)
Create acccounting ledgers. -![Tree](img/seconddaysetup_tree.png) +![Tree](img/seconddaysetup-tree.png)
@@ -23,7 +23,7 @@ To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page.
-![Ledger](img/seconddaysetup_accounts_jv.png) +![Ledger](img/seconddaysetup-accounts-jv.png)
@@ -34,7 +34,7 @@ To understand how to create opening entries in detail visit [Opening Entry](docs You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. -![Stock Opening](img/seconddaysetup_stock_opening.png) +![Stock Opening](img/seconddaysetup-stock-opening.png)
@@ -46,7 +46,7 @@ To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.o To setup HR, begin by creating individual employee records. -![Employee](img/seconddaysetup_hr.png) +![Employee](img/seconddaysetup-hr.png) To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index dc7acef0fd..a916837227 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -26,13 +26,13 @@ After completing the Lead form, assume that, this same lead is getting converted ##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status. -![Opportunity](img/thirddaysetup_opportunity_1.png) +![Opportunity](img/thirddaysetup-opportunity-1.png)
##### Step 2: Generate Opportunity from the selected Lead -![Opportunity](img/thirddaysetup_opportunity.png) +![Opportunity](img/thirddaysetup-opportunity.png) You can also generate an Opportunity directly from the Selling Page. @@ -43,7 +43,7 @@ You can also generate an Opportunity directly from the Selling Page. Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. -![Quotation](img/thirddaysetup_quotation.png) +![Quotation](img/thirddaysetup-quotation.png) You can also generate a Quotation directly from the Selling Page. @@ -54,7 +54,7 @@ You can also generate a Quotation directly from the Selling Page. Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. -![Sales Order](img/thirddaysetup_sales_order.png) +![Sales Order](img/thirddaysetup-sales-order.png) You can also generate a Sales Order directly from the Selling Page. @@ -65,7 +65,7 @@ You can also generate a Sales Order directly from the Selling Page. If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. -![Delivery Note](img/thirddaysetup_delivery_note.png) +![Delivery Note](img/thirddaysetup-delivery-note.png) > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) @@ -74,7 +74,7 @@ If your organisation has the practice of sending Delivery Note, this section wil Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. -![Sales Invoice](img/thirddaysetup_sales_invoice.png) +![Sales Invoice](img/thirddaysetup-sales-invoice.png)
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index f4938e9c07..c93a63212d 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -12,7 +12,7 @@ Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. -![Bill of Materials](img/fourthdaysetup_bom.png) +![Bill of Materials](img/fourthdaysetup-bom.png)
@@ -22,7 +22,7 @@ To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, c To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. -![Production Planning Page](img/fourthdaysetup_ppt.png) +![Production Planning Page](img/fourthdaysetup-ppt.png)
@@ -57,7 +57,7 @@ To go to Stock Entry, click on the Stock Icon and go to Stock Entry. To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. -[Delivery Note](img/fourthdaysetup_delivery_note.png) +![Delivery Note](img/fourthdaysetup-delivery-note.png)
From 0948b2a9d3604cb7755895a204b8a5415f38aec9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:04:18 +0530 Subject: [PATCH 30/43] [fix] [minor] repost order qty patch --- patches/december_2012/repost_ordered_qty.py | 25 +++++++++++-------- patches/patch_list.py | 1 + stock/doctype/serial_no/serial_no.py | 2 +- .../stock_ledger_entry/stock_ledger_entry.py | 6 ++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py index 2e3c690adf..e73b72663d 100644 --- a/patches/december_2012/repost_ordered_qty.py +++ b/patches/december_2012/repost_ordered_qty.py @@ -4,15 +4,18 @@ def execute(): import webnotes from webnotes.utils import flt - bins = webnotes.conn.sql("select item_code, warehouse, name, ordered_qty from `tabBin`") - for d in bins: - ordered_qty = webnotes.conn.sql(""" - select sum(ifnull(po_item.qty, 0) - ifnull(po_item.received_qty, 0)) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.parent = po.name and po.docstatus = 1 and po.status != 'Stopped' - and po_item.item_code = %s and po_item.warehouse = %s - """, (d[0], d[1])) - if flt(d[3]) != flt(ordered_qty[0][0]): - webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""", - (ordered_qty and ordered_qty[0][0] or 0, d[2])) \ No newline at end of file + for d in webnotes.conn.sql("select name, item_code, warehouse, ordered_qty from tabBin", + as_dict=1): + ordered_qty = webnotes.conn.sql(""" + select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + from `tabPurchase Order Item` po_item, `tabPurchase Order` po + where po_item.item_code=%s and po_item.warehouse=%s + and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po.status!='Stopped' and po.docstatus=1""", (d.item_code, d.warehouse)) + + if flt(d.ordered_qty) != flt(ordered_qty[0][0]): + webnotes.conn.set_value("Bin", d.name, "ordered_qty", flt(ordered_qty[0][0])) + + webnotes.conn.sql("""update tabBin set projected_qty = actual_qty + planned_qty + + indented_qty + ordered_qty - reserved_qty where name = %s""", d.name) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index f228acf97e..6a5d0f4f55 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -220,4 +220,5 @@ patch_list = [ "patches.september_2013.p04_unsubmit_serial_nos", "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", + "patches.october_2013.repost_ordered_qty", ] \ No newline at end of file diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 3922878280..d806287ecb 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days +from webnotes.utils import cint, getdate, cstr, flt, add_days import datetime from webnotes import msgprint, _, ValidationError diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 8fef889f72..bfb0f0aa92 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint -from webnotes.utils import cint, flt, getdate, cstr +from webnotes import msgprint +from webnotes.utils import flt, getdate from webnotes.model.controller import DocListController class DocType(DocListController): @@ -52,7 +52,7 @@ class DocType(DocListController): %(item_code)s at Warehouse %(warehouse)s \ as on %(posting_date)s %(posting_time)s""" % self.doc.fields) - sself.doc.fields.pop('batch_bal') + self.doc.fields.pop('batch_bal') def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] From 2658384edd45051d190dc902ffa523288bff4f50 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:07:42 +0530 Subject: [PATCH 31/43] [fix] [minor] repost order qty patch --- patches/october_2013/repost_ordered_qty.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 patches/october_2013/repost_ordered_qty.py diff --git a/patches/october_2013/repost_ordered_qty.py b/patches/october_2013/repost_ordered_qty.py new file mode 100644 index 0000000000..55827941b0 --- /dev/null +++ b/patches/october_2013/repost_ordered_qty.py @@ -0,0 +1,6 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +def execute(): + from patches.december_2012 import repost_ordered_qty + repost_ordered_qty.execute() \ No newline at end of file From 93c836c86dbe2b0f860addfed50dda485b5ab742 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:15:58 +0530 Subject: [PATCH 32/43] [fix] [minor] validate warehouse user --- stock/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/utils.py b/stock/utils.py index 1f501644ff..983ee72c05 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -209,7 +209,7 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): return wlist def validate_warehouse_user(warehouse): - if webnotes.session.user=="Administrator": + if webnotes.session.user=="Administrator" or not warehouse: return warehouse_users = [p[0] for p in webnotes.conn.sql("""select user from `tabWarehouse User` where parent=%s""", warehouse)] From 1797cfef634c6b154dc10fe192d1ebc444509ee4 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 11 Oct 2013 13:34:10 +0530 Subject: [PATCH 33/43] [fix] removed validation of conversion rate equals 1 from all transaction --- .../doctype/sales_invoice/sales_invoice.txt | 3 +- public/js/transaction.js | 39 ++++--------------- selling/doctype/quotation/quotation.txt | 3 +- selling/doctype/sales_order/sales_order.txt | 3 +- stock/doctype/delivery_note/delivery_note.txt | 5 +-- .../purchase_receipt/purchase_receipt.txt | 3 +- utilities/transaction_base.py | 9 +---- 7 files changed, 15 insertions(+), 50 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 516d1925a8..b168ba64fd 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-10-03 18:54:31", + "modified": "2013-10-11 13:12:38", "modified_by": "Administrator", "owner": "Administrator" }, @@ -225,7 +225,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which Customer Currency is converted to customer's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/public/js/transaction.js b/public/js/transaction.js index e12d1084e9..a7be5bdbf5 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -21,8 +21,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: wn.defaults.get_default("company"), fiscal_year: wn.defaults.get_default("fiscal_year"), is_subcontracted: "No", - conversion_rate: 1.0, - plc_conversion_rate: 1.0 }, function(fieldname, value) { if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) me.frm.set_value(fieldname, value); @@ -131,10 +129,16 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: function() { if(this.frm.doc.company && this.frm.fields_dict.currency) { + var company_currency = this.get_company_currency(); if(!this.frm.doc.currency) { - this.frm.set_value("currency", this.get_company_currency()); + this.frm.set_value("currency", company_currency); } + if(this.frm.doc.currency == company_currency) + this.frm.set_value("conversion_rate", 1.0); + if(this.frm.doc.price_list_currency == company_currency) + this.frm.set_value('plc_conversion_rate', 1.0); + this.frm.script_manager.trigger("currency"); } }, @@ -233,29 +237,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.calculate_taxes_and_totals(); }, - // serial_no: function(doc, cdt, cdn) { - // var me = this; - // var item = wn.model.get_doc(cdt, cdn); - // if (!item.item_code) { - // wn.call({ - // method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no', - // args: {serial_no: this.serial_no.$input.val()}, - // callback: function(r) { - // if (r.message) { - // var item_code = r.message[0].item_code; - // var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", - // this.frm.cscript.fname); - // child.item_code = item_code; - // me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); - // } - // else - // msgprint(wn._("Invalid Serial No.")); - // me.refresh(); - // } - // }); - // } - // }, - row_id: function(doc, cdt, cdn) { var tax = wn.model.get_doc(cdt, cdn); try { @@ -486,12 +467,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } var company_currency = this.get_company_currency(); - var valid_conversion_rate = this.frm.doc.conversion_rate ? - ((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) || - (this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) : - false; - if(!valid_conversion_rate) { + if(!this.frm.doc.conversion_rate) { wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + " 1 " + this.frm.doc.currency + " = [?] " + company_currency); } diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt index 3f97c980bc..62c36b432f 100644 --- a/selling/doctype/quotation/quotation.txt +++ b/selling/doctype/quotation/quotation.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:08", "docstatus": 0, - "modified": "2013-09-10 10:46:33", + "modified": "2013-10-11 13:21:07", "modified_by": "Administrator", "owner": "Administrator" }, @@ -257,7 +257,6 @@ "width": "100px" }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt index 94e63888e3..46a06b5bc4 100644 --- a/selling/doctype/sales_order/sales_order.txt +++ b/selling/doctype/sales_order/sales_order.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-18 12:39:59", "docstatus": 0, - "modified": "2013-08-09 14:46:17", + "modified": "2013-10-11 13:18:47", "modified_by": "Administrator", "owner": "Administrator" }, @@ -272,7 +272,6 @@ "width": "100px" }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/stock/doctype/delivery_note/delivery_note.txt b/stock/doctype/delivery_note/delivery_note.txt index f1493bb3bf..6834365b3f 100644 --- a/stock/doctype/delivery_note/delivery_note.txt +++ b/stock/doctype/delivery_note/delivery_note.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:09", "docstatus": 0, - "modified": "2013-08-09 14:46:32", + "modified": "2013-10-11 13:19:40", "modified_by": "Administrator", "owner": "Administrator" }, @@ -230,7 +230,7 @@ "depends_on": "eval:doc.po_no", "doctype": "DocField", "fieldname": "po_date", - "fieldtype": "Data", + "fieldtype": "Date", "hidden": 1, "label": "Customer's Purchase Order Date", "no_copy": 0, @@ -263,7 +263,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/stock/doctype/purchase_receipt/purchase_receipt.txt b/stock/doctype/purchase_receipt/purchase_receipt.txt index 11846435ce..f228a147c3 100755 --- a/stock/doctype/purchase_receipt/purchase_receipt.txt +++ b/stock/doctype/purchase_receipt/purchase_receipt.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-21 16:16:39", "docstatus": 0, - "modified": "2013-08-09 14:47:05", + "modified": "2013-10-11 13:20:13", "modified_by": "Administrator", "owner": "Administrator" }, @@ -215,7 +215,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which supplier's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 36231bf4f1..9921910a8a 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -432,14 +432,7 @@ def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, c company_currency = webnotes.conn.get_value("Company", company, "default_currency") - # parenthesis for 'OR' are necessary as we want it to evaluate as - # mandatory valid condition and (1st optional valid condition - # or 2nd optional valid condition) - valid_conversion_rate = (conversion_rate and - ((currency == company_currency and conversion_rate == 1.00) - or (currency != company_currency and conversion_rate != 1.00))) - - if not valid_conversion_rate: + if not conversion_rate: msgprint(_('Please enter valid ') + conversion_rate_label + (': ') + ("1 %s = [?] %s" % (currency, company_currency)), raise_exception=True) From eea2b34f4b69cdcdff269933de4ae76c5d859156 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 11 Oct 2013 18:31:33 +0530 Subject: [PATCH 34/43] [production] update planned and produced ty --- .../production_order/production_order.py | 11 +- .../production_order/test_production_order.py | 75 +++++++++++ patches/december_2012/repost_ordered_qty.py | 20 +-- patches/february_2013/repost_reserved_qty.py | 56 +-------- patches/october_2013/repost_planned_qty.py | 11 ++ patches/patch_list.py | 1 + stock/doctype/stock_entry/stock_entry.py | 78 +++++++----- stock/doctype/warehouse/warehouse.py | 93 +------------- stock/utils.py | 11 +- utilities/repost_stock.py | 119 ++++++++++++++++++ 10 files changed, 268 insertions(+), 207 deletions(-) create mode 100644 manufacturing/doctype/production_order/test_production_order.py create mode 100644 patches/october_2013/repost_planned_qty.py create mode 100644 utilities/repost_stock.py diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 719d149e64..b29b0f1e72 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -18,6 +18,9 @@ class DocType: self.doclist = doclist def validate(self): + if self.doc.docstatus == 0: + self.doc.status = "Draft" + import utilities utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "In Process", "Completed", "Cancelled"]) @@ -149,12 +152,6 @@ def get_item_details(item): @webnotes.whitelist() def make_stock_entry(production_order_id, purpose): production_order = webnotes.bean("Production Order", production_order_id) - - # validate already existing - ste = webnotes.conn.get_value("Stock Entry", { - "production_order":production_order_id, - "purpose": purpose - }, "name") stock_entry = webnotes.new_bean("Stock Entry") stock_entry.doc.purpose = purpose @@ -171,4 +168,4 @@ def make_stock_entry(production_order_id, purpose): stock_entry.doc.to_warehouse = production_order.doc.fg_warehouse stock_entry.run_method("get_items") - return [d.fields for d in stock_entry.doclist] + return [d.fields for d in stock_entry.doclist] \ No newline at end of file diff --git a/manufacturing/doctype/production_order/test_production_order.py b/manufacturing/doctype/production_order/test_production_order.py new file mode 100644 index 0000000000..9a75762ba4 --- /dev/null +++ b/manufacturing/doctype/production_order/test_production_order.py @@ -0,0 +1,75 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + + +from __future__ import unicode_literals +import unittest +import webnotes +from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory +from manufacturing.doctype.production_order.production_order import make_stock_entry + + +class TestProductionOrder(unittest.TestCase): + def test_planned_qty(self): + set_perpetual_inventory(0) + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("""delete from `tabBin`""") + webnotes.conn.sql("""delete from `tabGL Entry`""") + + pro_bean = webnotes.bean(copy = test_records[0]) + pro_bean.insert() + pro_bean.submit() + + from stock.doctype.stock_entry.test_stock_entry import test_records as se_test_records + mr1 = webnotes.bean(copy = se_test_records[0]) + mr1.insert() + mr1.submit() + + mr2 = webnotes.bean(copy = se_test_records[0]) + mr2.doclist[1].item_code = "_Test Item Home Desktop 100" + mr2.insert() + mr2.submit() + + stock_entry = make_stock_entry(pro_bean.doc.name, "Manufacture/Repack") + stock_entry = webnotes.bean(stock_entry) + + stock_entry.doc.fg_completed_qty = 4 + stock_entry.run_method("get_items") + stock_entry.submit() + + self.assertEqual(webnotes.conn.get_value("Production Order", pro_bean.doc.name, + "produced_qty"), 4) + self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test FG Item", + "warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6) + + return pro_bean.doc.name + + def test_over_production(self): + from stock.doctype.stock_entry.stock_entry import StockOverProductionError + pro_order = self.test_planned_qty() + + stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") + stock_entry = webnotes.bean(stock_entry) + + stock_entry.doc.fg_completed_qty = 15 + stock_entry.run_method("get_items") + stock_entry.insert() + + self.assertRaises(StockOverProductionError, stock_entry.submit) + + + +test_records = [ + [ + { + "bom_no": "BOM/_Test FG Item/001", + "company": "_Test Company", + "doctype": "Production Order", + "production_item": "_Test FG Item", + "qty": 10.0, + "fg_warehouse": "_Test Warehouse 1 - _TC", + "wip_warehouse": "_Test Warehouse - _TC", + "stock_uom": "Nos" + } + ] +] \ No newline at end of file diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py index e73b72663d..4c1d11d39b 100644 --- a/patches/december_2012/repost_ordered_qty.py +++ b/patches/december_2012/repost_ordered_qty.py @@ -3,19 +3,9 @@ def execute(): import webnotes - from webnotes.utils import flt - - for d in webnotes.conn.sql("select name, item_code, warehouse, ordered_qty from tabBin", - as_dict=1): - ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""", (d.item_code, d.warehouse)) + from utilities.repost_stock import get_ordered_qty, update_bin - if flt(d.ordered_qty) != flt(ordered_qty[0][0]): - webnotes.conn.set_value("Bin", d.name, "ordered_qty", flt(ordered_qty[0][0])) - - webnotes.conn.sql("""update tabBin set projected_qty = actual_qty + planned_qty + - indented_qty + ordered_qty - reserved_qty where name = %s""", d.name) \ No newline at end of file + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "ordered_qty": get_ordered_qty(d[0], d[1]) + }) \ No newline at end of file diff --git a/patches/february_2013/repost_reserved_qty.py b/patches/february_2013/repost_reserved_qty.py index 3a3353f918..5c41266c2a 100644 --- a/patches/february_2013/repost_reserved_qty.py +++ b/patches/february_2013/repost_reserved_qty.py @@ -4,54 +4,10 @@ import webnotes def execute(): webnotes.conn.auto_commit_on_many_writes = 1 - repost_reserved_qty() - webnotes.conn.auto_commit_on_many_writes = 0 + from utilities.repost_stock import get_reserved_qty, update_bin -def repost_reserved_qty(): - from webnotes.utils import flt - bins = webnotes.conn.sql("select item_code, warehouse, name, reserved_qty from `tabBin`") - i = 0 - for d in bins: - i += 1 - reserved_qty = webnotes.conn.sql(""" - select - sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) - from - ( - (select - qty as dnpi_qty, - ( - select qty from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_qty, - ( - select ifnull(delivered_qty, 0) from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_delivered_qty, - parent, name - from - ( - select qty, parent_detail_docname, parent, name - from `tabDelivery Note Packing Item` dnpi_in - where item_code = %s and warehouse = %s - and parenttype="Sales Order" - and item_code != parent_item - and exists (select * from `tabSales Order` so - where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') - ) dnpi) - union - (select qty as dnpi_qty, qty as so_item_qty, - ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name - from `tabSales Order Item` so_item - where item_code = %s and reserved_warehouse = %s - and exists(select * from `tabSales Order` so - where so.name = so_item.parent and so.docstatus = 1 - and so.status != 'Stopped')) - ) tab - where - so_item_qty >= so_item_delivered_qty - """, (d[0], d[1], d[0], d[1])) - - if flt(d[3]) != flt(reserved_qty[0][0]): - webnotes.conn.sql("""update `tabBin` set reserved_qty = %s where name = %s""", - (reserved_qty and reserved_qty[0][0] or 0, d[2])) \ No newline at end of file + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "reserved_qty": get_reserved_qty(d[0], d[1]) + }) + webnotes.conn.auto_commit_on_many_writes = 0 \ No newline at end of file diff --git a/patches/october_2013/repost_planned_qty.py b/patches/october_2013/repost_planned_qty.py new file mode 100644 index 0000000000..cfe47ca115 --- /dev/null +++ b/patches/october_2013/repost_planned_qty.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +def execute(): + import webnotes + from utilities.repost_stock import get_planned_qty, update_bin + + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "planned_qty": get_planned_qty(d[0], d[1]) + }) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 6a5d0f4f55..59e0b0cf87 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -221,4 +221,5 @@ patch_list = [ "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", "patches.october_2013.repost_ordered_qty", + "patches.october_2013.repost_planned_qty", ] \ 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 8d2e76490c..7d8130cc85 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -6,7 +6,7 @@ import webnotes import webnotes.defaults from webnotes.utils import cstr, cint, flt, comma_or, nowdate -from webnotes.model.doc import Document, addchild +from webnotes.model.doc import addchild from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint, _ @@ -21,6 +21,7 @@ class NotUpdateStockError(webnotes.ValidationError): pass class StockOverReturnError(webnotes.ValidationError): pass class IncorrectValuationRateError(webnotes.ValidationError): pass class DuplicateEntryForProductionOrderError(webnotes.ValidationError): pass +class StockOverProductionError(webnotes.ValidationError): pass from controllers.stock_controller import StockController @@ -56,12 +57,12 @@ class DocType(StockController): from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") - self.update_production_order(1) + self.update_production_order() self.make_gl_entries() def on_cancel(self): self.update_stock_ledger() - self.update_production_order(0) + self.update_production_order() self.make_cancel_gl_entries() def validate_fiscal_year(self): @@ -326,37 +327,44 @@ class DocType(StockController): self.make_sl_entries(sl_entries, self.doc.amended_from and 'Yes' or 'No') - def update_production_order(self, is_submit): + def update_production_order(self): + def _validate_production_order(pro_bean): + if flt(pro_bean.doc.docstatus) != 1: + webnotes.throw(_("Production Order must be submitted") + ": " + + self.doc.production_order) + + if pro_bean.doc.status == 'Stopped': + msgprint(_("Transaction not allowed against stopped Production Order") + ": " + + self.doc.production_order) + if self.doc.production_order: - # first perform some validations - # (they are here coz this fn is also called during on_cancel) - pro_obj = get_obj("Production Order", self.doc.production_order) - if flt(pro_obj.doc.docstatus) != 1: - msgprint("""You cannot do any transaction against - Production Order : %s, as it's not submitted""" - % (pro_obj.doc.name), raise_exception=1) - - if pro_obj.doc.status == 'Stopped': - msgprint("""You cannot do any transaction against Production Order : %s, - as it's status is 'Stopped'"""% (pro_obj.doc.name), raise_exception=1) - - # update bin - if self.doc.purpose == "Manufacture/Repack": - from stock.utils import update_bin - pro_obj.doc.produced_qty = flt(pro_obj.doc.produced_qty) + \ - (is_submit and 1 or -1 ) * flt(self.doc.fg_completed_qty) - args = { - "item_code": pro_obj.doc.production_item, - "warehouse": pro_obj.doc.fg_warehouse, - "posting_date": self.doc.posting_date, - "planned_qty": (is_submit and -1 or 1 ) * flt(self.doc.fg_completed_qty) - } - update_bin(args) + pro_bean = webnotes.bean("Production Order", self.doc.production_order) + _validate_production_order(pro_bean) + self.update_produced_qty(pro_bean) + self.update_planned_qty(pro_bean) - # update production order status - pro_obj.doc.status = (flt(pro_obj.doc.qty)==flt(pro_obj.doc.produced_qty)) \ - and 'Completed' or 'In Process' - pro_obj.doc.save() + def update_produced_qty(self, pro_bean): + if self.doc.purpose == "Manufacture/Repack": + produced_qty = flt(pro_bean.doc.produced_qty) + \ + (self.doc.docstatus==1 and 1 or -1 ) * flt(self.doc.fg_completed_qty) + + if produced_qty > flt(pro_bean.doc.qty): + webnotes.throw(_("Production Order") + ": " + self.doc.production_order + "\n" + + _("Total Manufactured Qty can not be greater than Planned qty to manufacture") + + "(%s/%s)" % (produced_qty, flt(pro_bean.doc.qty)), StockOverProductionError) + + status = 'Completed' if flt(produced_qty) >= flt(pro_bean.doc.qty) else 'In Process' + webnotes.conn.sql("""update `tabProduction Order` set status=%s, produced_qty=%s + where name=%s""", (status, produced_qty, self.doc.production_order)) + + def update_planned_qty(self, pro_bean): + from stock.utils import update_bin + update_bin({ + "item_code": pro_bean.doc.production_item, + "warehouse": pro_bean.doc.fg_warehouse, + "posting_date": self.doc.posting_date, + "planned_qty": (self.doc.docstatus==1 and -1 or 1 ) * flt(self.doc.fg_completed_qty) + }) def get_item_details(self, arg): arg = json.loads(arg) @@ -415,7 +423,8 @@ class DocType(StockController): return ret def get_items(self): - self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1) + self.doclist = filter(lambda d: d.parentfield!="mtn_details", self.doclist) + # self.doclist = self.doc.clear_table(self.doclist, 'mtn_details') pro_obj = None if self.doc.production_order: @@ -454,7 +463,7 @@ class DocType(StockController): "stock_uom": pro_obj.doc.stock_uom } }, bom_no=pro_obj.doc.bom_no) - + elif self.doc.purpose in ["Material Receipt", "Manufacture/Repack"]: if self.doc.purpose=="Material Receipt": self.doc.from_warehouse = "" @@ -471,6 +480,7 @@ class DocType(StockController): }, bom_no=self.doc.bom_no) self.get_stock_and_rate() + def get_bom_raw_materials(self, qty): """ diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index 58cf11bfdf..476a6f6478 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cint, flt, validate_email_add -from webnotes.model.code import get_obj from webnotes import msgprint, _ sql = webnotes.conn.sql @@ -83,103 +82,15 @@ class DocType: webnotes.conn.delete_doc("Account", old_warehouse_account) + from utilities.repost_stock import repost for item_code in items: - self.repost(item_code[0], self.doc.merge_with) + repost(item_code[0], self.doc.merge_with) webnotes.conn.auto_commit_on_many_writes = 0 msgprint("Warehouse %s merged into %s. Now you can delete warehouse: %s" % (self.doc.name, self.doc.merge_with, self.doc.name)) - - def repost(self, item_code, warehouse=None): - from stock.utils import get_bin - self.repost_actual_qty(item_code, warehouse) - - bin = get_bin(item_code, warehouse) - self.repost_reserved_qty(bin) - self.repost_indented_qty(bin) - self.repost_ordered_qty(bin) - self.repost_planned_qty(bin) - bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.planned_qty) \ - + flt(bin.doc.indented_qty) + flt(bin.doc.ordered_qty) - flt(bin.doc.reserved_qty) - bin.doc.save() - - - def repost_actual_qty(self, item_code, warehouse=None): - from stock.stock_ledger import update_entries_after - if not warehouse: - warehouse = self.doc.name - - update_entries_after({ "item_code": item_code, "warehouse": warehouse }) - - def repost_reserved_qty(self, bin): - reserved_qty = webnotes.conn.sql(""" - select - sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) - from - ( - select - qty as dnpi_qty, - ( - select qty from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_qty, - ( - select ifnull(delivered_qty, 0) from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_delivered_qty - from - ( - select qty, parent_detail_docname - from `tabDelivery Note Packing Item` dnpi_in - where item_code = %s and warehouse = %s - and parenttype="Sales Order" - and exists (select * from `tabSales Order` so - where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') - ) dnpi - ) tab - where - so_item_qty >= so_item_delivered_qty - """, (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.reserved_qty) != flt(reserved_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "reserved_qty", flt(reserved_qty[0][0])) - - - def repost_indented_qty(self, bin): - indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) - from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr - where pr_item.item_code=%s and pr_item.warehouse=%s - and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name - and pr.status!='Stopped' and pr.docstatus=1""" - , (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.indented_qty) != flt(indented_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "indented_qty", flt(indented_qty[0][0])) - - - def repost_ordered_qty(self, bin): - ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""" - , (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.ordered_qty) != flt(ordered_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "ordered_qty", flt(ordered_qty[0][0])) - - def repost_planned_qty(self, bin): - planned_qty = webnotes.conn.sql(""" - select sum(qty - produced_qty) from `tabProduction Order` - where production_item = %s and fg_warehouse = %s and status != "Stopped" - and docstatus=1""", (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.planned_qty) != flt(planned_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "planned_qty", flt(planned_qty[0][0])) - def on_trash(self): # delete bin bins = sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1) diff --git a/stock/utils.py b/stock/utils.py index 983ee72c05..0f801c74bc 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -393,13 +393,4 @@ def notify_errors(exceptions_list): Administrator""" % ("\n\n".join(["\n".join(msg) for msg in exceptions_list]),) from webnotes.profile import get_system_managers - sendmail(get_system_managers(), subject=subject, msg=msg) - - -def repost(): - """ - Repost everything! - """ - from webnotes.model.code import get_obj - for wh in webnotes.conn.sql("select name from tabWarehouse"): - get_obj('Warehouse', wh[0]).repost_stock() + sendmail(get_system_managers(), subject=subject, msg=msg) \ No newline at end of file diff --git a/utilities/repost_stock.py b/utilities/repost_stock.py new file mode 100644 index 0000000000..b46aae608f --- /dev/null +++ b/utilities/repost_stock.py @@ -0,0 +1,119 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +from webnotes.utils import flt + + +def repost(): + """ + Repost everything! + """ + webnotes.conn.auto_commit_on_many_writes = 1 + + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + repost_stock(d[0], d[1]) + + webnotes.conn.auto_commit_on_many_writes = 0 + +def repost_stock(item_code, warehouse): + repost_actual_qty(item_code, warehouse) + + if item_code and warehouse: + update_bin(item_code, warehouse, { + "reserved_qty": get_reserved_qty(item_code, warehouse), + "indented_qty": get_indented_qty(item_code, warehouse), + "ordered_qty": get_ordered_qty(item_code, warehouse), + "planned_qty": get_planned_qty(item_code, warehouse) + }) + +def repost_actual_qty(item_code, warehouse): + from stock.stock_ledger import update_entries_after + update_entries_after({ "item_code": item_code, "warehouse": warehouse }) + +def get_reserved_qty(item_code, warehouse): + reserved_qty = webnotes.conn.sql(""" + select + sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) + from + ( + (select + qty as dnpi_qty, + ( + select qty from `tabSales Order Item` + where name = dnpi.parent_detail_docname + ) as so_item_qty, + ( + select ifnull(delivered_qty, 0) from `tabSales Order Item` + where name = dnpi.parent_detail_docname + ) as so_item_delivered_qty, + parent, name + from + ( + select qty, parent_detail_docname, parent, name + from `tabDelivery Note Packing Item` dnpi_in + where item_code = %s and warehouse = %s + and parenttype="Sales Order" + and item_code != parent_item + and exists (select * from `tabSales Order` so + where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') + ) dnpi) + union + (select qty as dnpi_qty, qty as so_item_qty, + ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name + from `tabSales Order Item` so_item + where item_code = %s and reserved_warehouse = %s + and exists(select * from `tabSales Order` so + where so.name = so_item.parent and so.docstatus = 1 + and so.status != 'Stopped')) + ) tab + where + so_item_qty >= so_item_delivered_qty + """, (item_code, warehouse, item_code, warehouse)) + + return flt(reserved_qty[0][0]) if reserved_qty else 0 + +def get_indented_qty(item_code, warehouse): + indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) + from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr + where pr_item.item_code=%s and pr_item.warehouse=%s + and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name + and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse)) + + return flt(indented_qty[0][0]) if indented_qty else 0 + +def get_ordered_qty(item_code, warehouse): + ordered_qty = webnotes.conn.sql(""" + select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + from `tabPurchase Order Item` po_item, `tabPurchase Order` po + where po_item.item_code=%s and po_item.warehouse=%s + and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) + + return flt(ordered_qty[0][0]) if ordered_qty else 0 + +def get_planned_qty(item_code, warehouse): + planned_qty = webnotes.conn.sql(""" + select sum(qty - produced_qty) from `tabProduction Order` + where production_item = %s and fg_warehouse = %s and status != "Stopped" + and docstatus=1 and qty > produced_qty""", (item_code, warehouse)) + + return flt(planned_qty[0][0]) if planned_qty else 0 + + +def update_bin(item_code, warehouse, qty_dict=None): + from stock.utils import get_bin + bin = get_bin(item_code, warehouse) + mismatch = False + for fld, val in qty_dict.items(): + if flt(bin.doc.fields.get(fld)) != flt(val): + bin.doc.fields[fld] = flt(val) + mismatch = True + + if mismatch: + bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.ordered_qty) + \ + flt(bin.doc.indented_qty) + flt(bin.doc.planned_qty) - flt(bin.doc.reserved_qty) + + bin.doc.save() \ No newline at end of file From 7837827e30190b5090de47d91a0f01974c638e4c Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 11 Oct 2013 19:06:30 +0530 Subject: [PATCH 35/43] [fix] [minor] conversion arte related fixes --- .../doctype/sales_invoice/sales_invoice.js | 1 - controllers/accounts_controller.py | 11 +++-- controllers/selling_controller.py | 6 +-- public/js/transaction.js | 43 ++++++++++--------- utilities/transaction_base.py | 1 - 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 5220c0fa20..46e336f029 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -147,7 +147,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); } } - }, debit_to: function() { diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 927b24980f..3af9c7a547 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -52,7 +52,7 @@ class AccountsController(TransactionBase): msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") + self.doc.doctype + _(" can not be made."), raise_exception=1) - def set_price_list_currency(self, buying_or_selling): + def set_price_list_currency(self, buying_or_selling, for_validate=False): if self.meta.get_field("currency"): company_currency = get_company_currency(self.doc.company) @@ -60,14 +60,13 @@ class AccountsController(TransactionBase): fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \ else "buying_price_list" if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): - if not self.doc.price_list_currency: - self.doc.price_list_currency = webnotes.conn.get_value("Price List", - self.doc.fields.get(fieldname), "currency") + self.doc.price_list_currency = webnotes.conn.get_value("Price List", + self.doc.fields.get(fieldname), "currency") if self.doc.price_list_currency == company_currency: self.doc.plc_conversion_rate = 1.0 - elif not self.doc.plc_conversion_rate: + elif not self.doc.plc_conversion_rate or not for_validate: self.doc.plc_conversion_rate = self.get_exchange_rate( self.doc.price_list_currency, company_currency) @@ -77,7 +76,7 @@ class AccountsController(TransactionBase): self.doc.conversion_rate = self.doc.plc_conversion_rate elif self.doc.currency == company_currency: self.doc.conversion_rate = 1.0 - elif not self.doc.conversion_rate: + elif not self.doc.conversion_rate or not for_validate: self.doc.conversion_rate = self.get_exchange_rate(self.doc.currency, company_currency) diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 37674ee4bf..845ba859e0 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -20,7 +20,7 @@ class SellingController(StockController): # set contact and address details for customer, if they are not mentioned self.set_missing_lead_customer_details() - self.set_price_list_and_item_details() + self.set_price_list_and_item_details(for_validate) if self.doc.fields.get("__islocal"): self.set_taxes("other_charges", "charge") @@ -38,8 +38,8 @@ class SellingController(StockController): if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): self.doc.fields[fieldname] = val - def set_price_list_and_item_details(self): - self.set_price_list_currency("Selling") + def set_price_list_and_item_details(self, for_validate=False): + self.set_price_list_currency("Selling", for_validate) self.set_missing_item_details(get_item_details) def get_other_charges(self): diff --git a/public/js/transaction.js b/public/js/transaction.js index a7be5bdbf5..79ea53623f 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -39,18 +39,19 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ }, onload_post_render: function() { - if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.customer) { - var me = this; - return this.frm.call({ - doc: this.frm.doc, - method: "onload_post_render", - freeze: true, - callback: function(r) { - // remove this call when using client side mapper - me.set_default_values(); - me.set_dynamic_labels(); - } - }); + if(this.frm.doc.__islocal && this.frm.doc.company && + !this.frm.doc.customer && !this.frm.doc.is_pos) { + var me = this; + return this.frm.call({ + doc: this.frm.doc, + method: "onload_post_render", + freeze: true, + callback: function(r) { + // remove this call when using client side mapper + me.set_default_values(); + me.set_dynamic_labels(); + } + }); } }, @@ -130,14 +131,16 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: function() { if(this.frm.doc.company && this.frm.fields_dict.currency) { var company_currency = this.get_company_currency(); - if(!this.frm.doc.currency) { + if (!this.frm.doc.currency) { this.frm.set_value("currency", company_currency); } - if(this.frm.doc.currency == company_currency) + if (this.frm.doc.currency == company_currency) { this.frm.set_value("conversion_rate", 1.0); - if(this.frm.doc.price_list_currency == company_currency) + } + if (this.frm.doc.price_list_currency == company_currency) { this.frm.set_value('plc_conversion_rate', 1.0); + } this.frm.script_manager.trigger("currency"); } @@ -150,15 +153,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ currency: function() { var me = this; this.set_dynamic_labels(); - + var company_currency = this.get_company_currency(); if(this.frm.doc.currency !== company_currency) { this.get_exchange_rate(this.frm.doc.currency, company_currency, function(exchange_rate) { - if(exchange_rate) { - me.frm.set_value("conversion_rate", exchange_rate); - me.conversion_rate(); - } + me.frm.set_value("conversion_rate", exchange_rate); + me.conversion_rate(); }); } else { this.conversion_rate(); @@ -172,7 +173,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) { this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); } - + this.calculate_taxes_and_totals(); }, diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 9921910a8a..0f4d6bcacd 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -144,7 +144,6 @@ class TransactionBase(StatusUpdater): def get_customer_address(self, args): args = load_json(args) - webnotes.errprint(args) ret = { 'customer_address' : args["address"], 'address_display' : get_address_display(args["address"]), From 287ce383bed6a9956f56e0257cf94dd4624a0657 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 14 Oct 2013 10:24:22 +0530 Subject: [PATCH 36/43] [docs] website content added --- docs/user/website/docs.user.website.blog.md | 9 +++++-- docs/user/website/docs.user.website.setup.md | 25 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/user/website/docs.user.website.blog.md b/docs/user/website/docs.user.website.blog.md index ec035a0344..b71836e016 100644 --- a/docs/user/website/docs.user.website.blog.md +++ b/docs/user/website/docs.user.website.blog.md @@ -15,6 +15,11 @@ To create a new blog, just create a new Blog from: ![Blog](img/blog.png) -You can format the blog using the same Markdown format +You can format a blog using the Markdown format.You can also access your blog by going to the page “blog.html”. + + +#### A sample blog-page. + + +![Blog](img/blog-look.png) -You can access your blog by going to the page “blog.html” diff --git a/docs/user/website/docs.user.website.setup.md b/docs/user/website/docs.user.website.setup.md index 3249637c2d..4d1d7c7c07 100644 --- a/docs/user/website/docs.user.website.setup.md +++ b/docs/user/website/docs.user.website.setup.md @@ -29,11 +29,36 @@ To define the Top Bar Menus, Brand, Footers and Home Page, go to: > Website > Website Settings +#### Step 1: Landing Page Details ![Website Setting](img/website-settings.png)
+#### Step 2: Banner Details + +![Website Setting](img/website-settings-1.png) + +
+ +#### Step 3: Top Bar Labels + +![Website Setting](img/website-settings-2.png) + +> Note: Create seperate web pages which will be linked to the main web-icons like company, contact, products etc. + +
+#### Step 4: Footer Details + +![Website Setting](img/website-settings-3.png) + +A website can be generated once all the settings and style requirements are added. + +A sample website generated by ERPNext would look like this. + +![Website](img/website-settings-4.png) + +
#### Top Menu From 74ec868968811119d5b53de98b611de24612759c Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 13:41:55 +0530 Subject: [PATCH 37/43] [fix] [minor] added for validate in buying controller --- controllers/buying_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 25d76aa66d..1115b49677 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -30,7 +30,7 @@ class BuyingController(StockController): super(BuyingController, self).set_missing_values(for_validate) self.set_supplier_from_item_default() - self.set_price_list_currency("Buying") + self.set_price_list_currency("Buying", for_validate) # set contact and address details for supplier, if they are not mentioned if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address): From b5e74d7fa69a59962297b6401a8677816b8b107a Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 14 Oct 2013 14:20:03 +0530 Subject: [PATCH 38/43] [docs] minor name details added --- docs/user/docs.user.md | 10 ++-- .../docs.user.five_day_setup.day_1.md | 2 +- .../docs.user.five_day_setup.day_2.md | 2 +- .../docs.user.five_day_setup.day_3.md | 2 +- .../docs.user.five_day_setup.day_4.md | 2 +- .../docs.user.five_day_setup.day_5.md | 2 +- .../intro/docs.user.implement.strategy.md | 1 + docs/user/stock/docs.user.stock.item.md | 56 +++++++++++++++++++ 8 files changed, 67 insertions(+), 10 deletions(-) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 53e5534185..5c6588272e 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -31,11 +31,11 @@ Contents 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) 1. [Five-Day-Setup](docs.user.five_day_setup.html) - 1. [Day-1](docs.user.five_day_setup.day_1.html) - 1. [Day-2](docs.user.five_day_setup.day_2.html) - 1. [Day-3](docs.user.five_day_setup.day_3.html) - 1. [Day-4](docs.user.five_day_setup.day_4.html) - 1. [Day-5](docs.user.five_day_setup.day_5.html) + 1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html) + 1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html) + 1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html) + 1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html) + 1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index a64f833bd7..9f39810f1a 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-1" + "_label": "Day-1: Setup Customer, Item, and Supplier" } --- Login to your ERPNext account with the User ID and Password sent through the mail. diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index 11e13e2ea9..d2e826f5e7 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-2" + "_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR" } --- diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index a916837227..4a15f5c90b 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-3" + "_label": "Day-3: Sales Cycle and Purchase Cycle" } --- After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index c93a63212d..cdd43f0a75 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-4" + "_label": "Day-4: Manufacturing Cycle and Accounting Reports" } --- diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index b69fccd6ed..d0572db3c2 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-5" + "_label": "Day-5: Projects Calendar and Website" } --- diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 735fe1e525..e077a90e56 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -10,6 +10,7 @@ Before you start managing your Operations in EPRNext, you must first become fami ### Test Phase - Read the Manual +- Follow the Five-Day-Setup Module or the instructions given below. - Create your first Customer, Supplier and Item. Add a few more so you get familiar with them. - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index 76a83a2afa..f7746c4842 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -91,3 +91,59 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi Visit [Manufacturing](docs.user.mfg.html) and [Website](docs.user.website.html) to understand these topics in detail. + +### Listing Item on Website + +To list your Item on the Website, fill the Item details and save the file. Once the file is saved, a plus (+) button will appear next to the Image icon. Click on the plus button and add your Item image. The html code will be generated automatically. + +##### Step 1: Save Image + +![Webimage](img/item-webimage.png) + +
+ +##### Step 2: Check the 'Show in Website' box. + +Under the Website section, please check the box that says 'show in Website'. Once the box is checked, the page will display other fields for entering information. + +![Webimage](img/item-webimage-1.png) + +
+ + +##### Step 3: Enter Website Details + +![Webimage](img/item-webimage-2.png) + + +The page name will be generated automatically. Mention the Item-Group under which the Item will be displayed. + +#### Item Groups + +Mention the Item Group under this column. If you wish to list your Item under the broad category products, name your Item Group as Products. In case you have various varieties of Item and want to classify them under different names, make Item Groups with those names and check the box that says 'show in Website'. For Example, if you wish to create a category called 'Bags', create a Item Group named Bags. + + +![Item Group](img/itemgroup-webimage-bags.png) + +Once the Item Group is created go to the Website Settings page under Website. Enter the Label, Url, and Parent Label. + + +![Item Group](img/itemgroup-website-settings.png) + +
+ +#### Webpage labels + +![Webpage](img/webpage-labels.png) + +Add more Items under a particular Item Group. + +To add more Items under a certain Label, mention the Item Group on the Item Page. The Items will be added automatically on the Webpage, under the Item Group Label. For Example, To add Item-Kiddies Bag and Butterfly Print Bag, check the 'Show in Website'box. The Items will be placed under the Label Bags on the Webpage. + +![Item Group](img/itemgroup-websettings.png) + +
+ +Item Group Display + +![Item Group Display](img/webpage-itemgroup-display.png) \ No newline at end of file From 1a60fd8906068013bd4ecaf0769355d5828f2af9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 14 Oct 2013 14:27:08 +0530 Subject: [PATCH 39/43] [fix] [minor] fixes in reposting of ordered, indented and planned qty --- utilities/repost_stock.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utilities/repost_stock.py b/utilities/repost_stock.py index b46aae608f..735930486e 100644 --- a/utilities/repost_stock.py +++ b/utilities/repost_stock.py @@ -76,29 +76,29 @@ def get_reserved_qty(item_code, warehouse): return flt(reserved_qty[0][0]) if reserved_qty else 0 def get_indented_qty(item_code, warehouse): - indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) + indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0)) from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr where pr_item.item_code=%s and pr_item.warehouse=%s - and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name + and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse)) return flt(indented_qty[0][0]) if indented_qty else 0 def get_ordered_qty(item_code, warehouse): ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor) from `tabPurchase Order Item` po_item, `tabPurchase Order` po where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) return flt(ordered_qty[0][0]) if ordered_qty else 0 def get_planned_qty(item_code, warehouse): planned_qty = webnotes.conn.sql(""" - select sum(qty - produced_qty) from `tabProduction Order` + select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order` where production_item = %s and fg_warehouse = %s and status != "Stopped" - and docstatus=1 and qty > produced_qty""", (item_code, warehouse)) + and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse)) return flt(planned_qty[0][0]) if planned_qty else 0 From c06cbd5b7128ba5683918f4e3204a7dde1057188 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 15:55:19 +0530 Subject: [PATCH 40/43] [docs] [cleanup] five day setup docs cleanup --- docs/user/docs.user.md | 10 ++-- .../docs.user.five_day_setup.day_1.md | 8 +--- .../docs.user.five_day_setup.day_2.md | 11 +++-- .../docs.user.five_day_setup.day_3.md | 28 ++++++----- .../docs.user.five_day_setup.day_4.md | 46 ++++++++----------- .../docs.user.five_day_setup.day_5.md | 14 +++--- .../docs.user.five_day_setup.md | 3 +- .../docs.user.knowledge.attachment_csv.md | 2 +- docs/user/setup/docs.user.setup.md | 2 +- 9 files changed, 56 insertions(+), 68 deletions(-) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 53e5534185..5c6588272e 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -31,11 +31,11 @@ Contents 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) 1. [Five-Day-Setup](docs.user.five_day_setup.html) - 1. [Day-1](docs.user.five_day_setup.day_1.html) - 1. [Day-2](docs.user.five_day_setup.day_2.html) - 1. [Day-3](docs.user.five_day_setup.day_3.html) - 1. [Day-4](docs.user.five_day_setup.day_4.html) - 1. [Day-5](docs.user.five_day_setup.day_5.html) + 1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html) + 1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html) + 1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html) + 1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html) + 1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index a64f833bd7..80215373ba 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-1" + "_label": "Day-1: Setup Customer,Item, and Supplier" } --- Login to your ERPNext account with the User ID and Password sent through the mail. @@ -10,10 +10,8 @@ After logging into your account you will receive a pop-up form to fill. Please f #### Form Part I ![1st Form](img/firstdaysetup-1.png) -
+

#### Form Part II -
- To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) @@ -61,8 +59,6 @@ To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.h
#### Setup Page - Suppliers -
- On the Setup page go to Supplier. ![Supplier](img/firstdaysetup-supplier.png) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index 11e13e2ea9..f01662319b 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -1,11 +1,11 @@ --- { - "_label": "Day-2" + "_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR" } --- -#### Setup Page- Accounts - +#### Setup Page - Accounts +
Go to the Accounts icon and make ledgers under Chart of Accounts. ![Accounts](img/seconddaysetup-accounts.png) @@ -21,8 +21,6 @@ Create acccounting ledgers. To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. -
- ![Ledger](img/seconddaysetup-accounts-jv.png)
@@ -30,6 +28,8 @@ To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html). +
+ #### Opening Stock You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. @@ -40,6 +40,7 @@ You can upload your opening stock in the system using Stock Reconciliation. Stoc To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html). +
#### Setup Page - HR Setup diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index a916837227..20536cabf9 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-3" + "_label": "Day-3: Sales Cycle and Purchase Cycle" } --- After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. @@ -8,8 +8,10 @@ After completing the set-up and account opening process, it is advisable to com ### Sales Cycle -Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) +Complete a standard Sales Cycle. +> Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) +
#### Lead To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. @@ -20,6 +22,7 @@ Fill the Lead form. > To understand Lead in detail, visit [Lead](docs.user.selling.lead.html) +
#### Opportunity After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page. @@ -38,7 +41,7 @@ You can also generate an Opportunity directly from the Selling Page. > To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html). - +
#### Quotation Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. @@ -49,7 +52,7 @@ You can also generate a Quotation directly from the Selling Page. > To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html) - +
#### Sales Order Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. @@ -60,6 +63,7 @@ You can also generate a Sales Order directly from the Selling Page. > To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html). +
#### Delivery Note If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. @@ -69,7 +73,7 @@ If your organisation has the practice of sending Delivery Note, this section wil > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) - +
#### Sales Invoice Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. @@ -91,9 +95,10 @@ A Journal Voucher or a payment entry can be generated directly from the Sales In ### Purchase Cycle -Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). - +Complete a standard Purchase Cycle. +> Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). +
#### Material Request To create a Material Request, go to Stock/Buying and Click on Material Request. @@ -102,6 +107,7 @@ To create a Material Request, go to Stock/Buying and Click on Material Request. > To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html) +
#### Purchase Order To create a Purchase Order go to Buying and click on Purchase Order @@ -110,26 +116,24 @@ To create a Purchase Order go to Buying and click on Purchase Order > To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html) +
#### Purchase Receipt To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt. ![Purchase Receipt](img/thirddaysetup-purchase-receipt.png) -
>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html)
-#### Payment( Journal Voucher) +#### Payment (Journal Voucher) Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices. ![Payment Entry](img/thirddaysetup-payment-entry.png) -
-> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). - +> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index c93a63212d..eb2b58b1ea 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -1,86 +1,76 @@ --- { - "_label": "Day-4" + "_label": "Day-4: Manufacturing Cycle and Accounting Reports" } --- ### Manufacturing Cycle -Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (material issue) > Stock Entry (sales return) +Complete a manufacturing cycle (if applicable). +> BOM > Production Planning Tool > Production Order > Stock Entry (Material Issue) > Stock Entry (Sales Return) +
#### Bill of Materials To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. ![Bill of Materials](img/fourthdaysetup-bom.png) -
- > To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html) +
#### Production Planning Tool To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. ![Production Planning Page](img/fourthdaysetup-ppt.png) -
- > To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html) - +
#### Production Order To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. ![Production Order](img/fourthdaysetup-po.png) -
- > To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html) +
#### Stock Entry To go to Stock Entry, click on the Stock Icon and go to Stock Entry. ![Stock Entry](img/fourthdaysetup-stock.png) +> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html). + +> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html). +
- -> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html) - - -> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html) - - #### Delivery Note To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. ![Delivery Note](img/fourthdaysetup-delivery-note.png) -
- > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) - - +
#### Warehouse To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. ![Warehouse](img/fourthdaysetup-warehouse.png) +> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) +
- -> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) - - #### Accounts Make a few Journal Vouchers. Generate some Accounting Reports. -#### Journal Voucher. +#### Journal Voucher To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. @@ -88,9 +78,9 @@ To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Jo > To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) -#### Accounting Reports +
+### Accounting Reports Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register. -> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) - +> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index b69fccd6ed..e8a6f087b1 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-5" + "_label": "Day-5: Projects, Calendar, and Website" } --- @@ -8,6 +8,7 @@ ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people. +
#### Tasks Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project. @@ -16,19 +17,16 @@ To create a Task, go to Project and click on Task. ![Tasks](img/fifthdaysetup-tasks.png) -
- - -> To understand Projects in detail, visit [Projects](docs.user.projects.html) +> To understand Projects in detail, visit [Projects](docs.user.projects.html). > To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html) +
#### Calendar > To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html) - +
#### Website -> To understand Website in detail, visit [Website](docs.user.website.html) - +> To understand Website in detail, visit [Website](docs.user.website.html) \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.md b/docs/user/five_day_setup/docs.user.five_day_setup.md index d296914f9e..90aeb56c22 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.md @@ -45,5 +45,4 @@ The setup help is divided into day-wise instructions for 5 consecutive days. - Projects - Calendar -- Website - +- Website \ No newline at end of file diff --git a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md index 311934d7f4..eecc42ddcf 100644 --- a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md +++ b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md @@ -1,6 +1,6 @@ --- { - "_label": "Attachement and CSV files" + "_label": "Attachment and CSV files" } --- diff --git a/docs/user/setup/docs.user.setup.md b/docs/user/setup/docs.user.setup.md index fa9680a062..585811f66e 100644 --- a/docs/user/setup/docs.user.setup.md +++ b/docs/user/setup/docs.user.setup.md @@ -18,7 +18,7 @@ "docs.user.setup.email", "docs.user.setup.sms", "docs.user.setup.taxes", - "docs.user.setup.price_lists", + "docs.user.setup.price_list", "docs.user.setup.opening", "docs.user.setup.pos_setting", "docs.user.setup.third_party_backups" From 570b1070a8bf4478f8c60cd77c2810572658d626 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 14 Oct 2013 17:54:28 +0530 Subject: [PATCH 41/43] [fix] [minor] stock balance report for serialized item --- public/js/stock_grid_report.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index 46370d27f6..495ea43e40 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -28,9 +28,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ var value_diff = (rate * add_qty); if(add_qty) - wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); - - if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl); + wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); } else { // outgoing if(sl.serial_no) { @@ -113,7 +111,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ $.each(wn.report_dump.data["Stock Ledger Entry"], function(i, sle) { if(sle.qty > 0 && sle.serial_no) { $.each(sle.serial_no.trim().split("\n"), function(i, sr) { - if(sr && sle.incoming_rate !== undefined) { + if(sr && sle.incoming_rate !== undefined + && !serialized_buying_rates[sr.trim().toLowerCase()]) { serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate); } }); From 1e58ecdc74218826800425d01ac68ab58384b91b Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 18:22:26 +0530 Subject: [PATCH 42/43] [docs] updated pos and price list docs --- docs/user/accounts/docs.user.accounts.pos.md | 19 ++++++++++--------- docs/user/setup/docs.user.setup.price_list.md | 13 ++++++++++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/user/accounts/docs.user.accounts.pos.md b/docs/user/accounts/docs.user.accounts.pos.md index 654a5d6dfa..7bd668ef72 100644 --- a/docs/user/accounts/docs.user.accounts.pos.md +++ b/docs/user/accounts/docs.user.accounts.pos.md @@ -13,33 +13,34 @@ You can make a Sales Invoice of type POS by checking on “Is POS”. When you c - Update Stock: If this is checked, Stock Ledger Entries will be made when you “Submit” this Sales Invoice thereby eliminating the need for a separate Delivery Note.
 - In your Items table, update inventory information like Warehouse (saved as default), Serial Number, or Batch Number if applicable.
 -- Update Payment Details like your Bank / Cash Account, paid amount etc.
 +- Update Payment Details like your Bank / Cash Account, Paid amount etc.
 - If you are writing off certain amount. For example when you receive extra cash as a result of not having exact denomination of change, check on ‘Write off Outstanding Amount’ and set the Account. -Setup [POS Setting](docs.user.setup.pos_setting.html) #### Enable POS View -Sales Invoice has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred. +- Every Sales & Purchase documents has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred. > Setup > Show/Hide Features ![POS View](img/pos-features-setup.png) +- Setup [POS Setting](docs.user.setup.pos_setting.html) + ### Adding an Item -At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode. +At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode / Serial No. **Select Item** - To select a product click on the Item image and add it into the cart. A cart is an area that prepares a customer for checkout by allowing to edit product information, adjust taxes and add discounts. -**Barcode** - A Barcode is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode in the barcode box and pause for a second. The Item will be automatically added to the cart. +**Barcode / Serial No** - A Barcode / Serial No is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode / Serial No in the box as shown in the image below and pause for a second, the item will be automatically added to the cart. ![POS](img/pos-add-item.png) > Tip: To change the quantity of an Item, enter your desired quantity in the quantity box. These are mostly used if the same Item is purchased in bulk. -If your product list is very long use the universal search field, to type the product name and select faster. +If your product list is very long use the Search field, type the product name in Search box. ### Removing an Item @@ -48,7 +49,7 @@ There are two ways to remove an Item. - Select an Item by clicking on the row of that Item from Item cart. Then click on “Del” button. OR -- Type 0 in the ‘select quantity’ field to delete the record. +- Enter 0(zero) quantity of any item to delete that item. To remove multiple Items together, select multiple rows & click on “Del” button. @@ -62,11 +63,11 @@ After all the Items and their quantities are added into the cart, you are ready 1. Click on “Make Payment” to get the Payment window. 1. Select your “Mode of Payment”. -1. Click on “Pay” button to Save the Sales Invoice. +1. Click on “Pay” button to Save the document. ![POS Payment](img/pos-make-payment.png) -Submit the document to finalise the record. After the Invoice is submitted, you can either print an invoice or email it directly to the customer. +Submit the document to finalise the record. After the document is submitted, you can either print or email it directly to the customer. #### Accounting entries (GL Entry) for a Point of Sale: diff --git a/docs/user/setup/docs.user.setup.price_list.md b/docs/user/setup/docs.user.setup.price_list.md index 021df09041..7214fff514 100644 --- a/docs/user/setup/docs.user.setup.price_list.md +++ b/docs/user/setup/docs.user.setup.price_list.md @@ -7,7 +7,7 @@ A Price List is a place where different rate plans can be stored. It’s a name An Item can have multiple prices based on customer, currency, region, shipping cost etc, which can be stored as different rate plans. In ERPNext, you are required to store all the lists seperately. Buying Price List is different from Selling Price List and thus is stored separately. -> Selling > Price List +> Setup > Price List ![Price-List](img/price-lists.png) @@ -15,7 +15,14 @@ An Item can have multiple prices based on customer, currency, region, shipping c > For multiple currencies, maintain multiple Price Lists. +
+### Add Item in Price List -To add a new Item to the Price List, add the Item Code and its rate in the Item Prices table. +> Setup > Item Price -You can also import Item Prices via [Data Import Tool](docs.user.setup.data_import.html) \ No newline at end of file +- Enter Price List and Item Code, Valid for Buying or Selling, Item Name & Item Description will be automatically fetched. +- Enter Rate and save the document. + +![Item-Price](img/item-price.png) + +For bulk upload of Item Prices, use [Data Import Tool](docs.user.setup.data_import.html) \ No newline at end of file From bfeae2da707699cb3e881b017545caf1e4f5f061 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 15 Oct 2013 11:16:38 +0530 Subject: [PATCH 43/43] [cleanup] [minor] removed conversion rate from pos setting --- accounts/doctype/pos_setting/pos_setting.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/accounts/doctype/pos_setting/pos_setting.txt b/accounts/doctype/pos_setting/pos_setting.txt index 2420ad5503..7eda7fd62f 100755 --- a/accounts/doctype/pos_setting/pos_setting.txt +++ b/accounts/doctype/pos_setting/pos_setting.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 12:15:51", "docstatus": 0, - "modified": "2013-08-28 19:13:42", + "modified": "2013-10-15 11:12:02", "modified_by": "Administrator", "owner": "Administrator" }, @@ -80,16 +80,6 @@ "read_only": 0, "reqd": 1 }, - { - "doctype": "DocField", - "fieldname": "conversion_rate", - "fieldtype": "Float", - "label": "Conversion Rate", - "oldfieldname": "conversion_rate", - "oldfieldtype": "Currency", - "read_only": 0, - "reqd": 1 - }, { "doctype": "DocField", "fieldname": "selling_price_list",