Merge pull request #5180 from nabinhait/stock_entry_actual_qty

[fix] Set actual qty onload of the draft stock entry. Fixed #5172
diff --git a/.travis.yml b/.travis.yml
index 12a73c9..966dfd3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,7 @@
   - sudo bash setup_frappe.sh --skip-setup-bench --mysql-root-password travis
   - sudo pip install --upgrade pip
   - rm $TRAVIS_BUILD_DIR/.git/shallow
-  - cd ~/ && bench init frappe-bench --frappe-path https://github.com/frappe/frappe.git --frappe-branch develop
+  - bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
   - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
 
 script:
diff --git a/ci/fix-mariadb.sh b/ci/fix-mariadb.sh
deleted file mode 100755
index 886ec5e..0000000
--- a/ci/fix-mariadb.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-# stolen from http://cgit.drupalcode.org/octopus/commit/?id=db4f837
-includedir=`mysql_config --variable=pkgincludedir`
-thiscwd=`pwd`
-_THIS_DB_VERSION=`mysql -V 2>&1 | tr -d "\n" | cut -d" " -f6 | awk '{ print $1}' | cut -d"-" -f1 | awk '{ print $1}' | sed "s/[\,']//g"`
-if [ "$_THIS_DB_VERSION" = "5.5.40" ] && [ ! -e "$includedir-$_THIS_DB_VERSION-fixed.log" ] ; then
-  cd $includedir
-  sudo patch -p1 < $thiscwd/ci/my_config.h.patch &> /dev/null
-  sudo touch $includedir-$_THIS_DB_VERSION-fixed.log
-fi
diff --git a/ci/my_config.h.patch b/ci/my_config.h.patch
deleted file mode 100644
index 5247b5b..0000000
--- a/ci/my_config.h.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff -burp a/my_config.h b/my_config.h
---- a/my_config.h	2014-10-09 19:32:46.000000000 -0400
-+++ b/my_config.h	2014-10-09 19:35:12.000000000 -0400
-@@ -641,17 +641,4 @@
- #define SIZEOF_TIME_T 8
- /* #undef TIME_T_UNSIGNED */
-
--/*
--  stat structure (from <sys/stat.h>) is conditionally defined
--  to have different layout and size depending on the defined macros.
--  The correct macro is defined in my_config.h, which means it MUST be
--  included first (or at least before <features.h> - so, practically,
--  before including any system headers).
--
--  __GLIBC__ is defined in <features.h>
--*/
--#ifdef __GLIBC__
--#error <my_config.h> MUST be included first!
--#endif
--
- #endif
-
diff --git a/erpnext/__version__.py b/erpnext/__version__.py
index 9ebc832..38183fb 100644
--- a/erpnext/__version__.py
+++ b/erpnext/__version__.py
@@ -1,2 +1,2 @@
 from __future__ import unicode_literals
-__version__ = '6.27.5'
+__version__ = '6.27.7'
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.js b/erpnext/accounts/doctype/tax_rule/tax_rule.js
index 4c35370..935ea62 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.js
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.js
@@ -19,19 +19,6 @@
 	frappe.ui.form.trigger("Tax Rule", "tax_type");
 })
 
-frappe.ui.form.on("Tax Rule", "use_for_shopping_cart", function(frm) {
-	if(!frm.doc.use_for_shopping_cart && 
-			(frappe.get_list("Tax Rule", {"use_for_shopping_cart":1}).length == 0)) {
-		frappe.model.get_value("Shopping Cart Settings", "Shopping Cart Settings", 
-				"enabled", function(docfield) {
-			if(docfield.enabled){
-				frm.set_value("use_for_shopping_cart", 1);
-				frappe.throw(__("Shopping Cart is enabled"));
-			}
-		});
-	}
-})
-
 frappe.ui.form.on("Tax Rule", "customer", function(frm) {
 	frappe.call({
 		method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
@@ -64,4 +51,4 @@
 			}
 		}
 	});
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py
index 7b62082..ce20d3a 100644
--- a/erpnext/accounts/doctype/tax_rule/tax_rule.py
+++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py
@@ -6,7 +6,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import cstr
+from frappe.utils import cstr, cint
 
 class IncorrectCustomerGroup(frappe.ValidationError): pass
 class IncorrectSupplierType(frappe.ValidationError): pass
@@ -20,15 +20,16 @@
 		self.validate_tax_template()
 		self.validate_date()
 		self.validate_filters()
+		self.validate_use_for_shopping_cart()
 
 	def validate_tax_template(self):
 		if self.tax_type== "Sales":
-			self.purchase_tax_template = self.supplier = self.supplier_type= None
+			self.purchase_tax_template = self.supplier = self.supplier_type = None
 			if self.customer:
 				self.customer_group = None
 
 		else:
-			self.sales_tax_template= self.customer = self.customer_group= None
+			self.sales_tax_template = self.customer = self.customer_group = None
 
 			if self.supplier:
 				self.supplier_type = None
@@ -81,6 +82,15 @@
 			if tax_rule[0].priority == self.priority:
 				frappe.throw(_("Tax Rule Conflicts with {0}".format(tax_rule[0].name)), ConflictingTaxRule)
 
+	def validate_use_for_shopping_cart(self):
+		'''If shopping cart is enabled and no tax rule exists for shopping cart, enable this one'''
+		if (not self.use_for_shopping_cart
+			and cint(frappe.db.get_single_value('Shopping Cart Settings', 'enabled'))
+			and not frappe.db.get_value('Tax Rule', {'use_for_shopping_cart': 1, 'name': ['!=', self.name]})):
+
+			self.use_for_shopping_cart = 1
+			frappe.msgprint(_("Enabling 'Use for Shopping Cart', as Shopping Cart is enabled and there should be at least one Tax Rule for Shopping Cart"))
+
 @frappe.whitelist()
 def get_party_details(party, party_type, args=None):
 	out = {}
@@ -109,11 +119,11 @@
 def get_tax_template(posting_date, args):
 	"""Get matching tax rule"""
 	args = frappe._dict(args)
-	conditions = ["""(from_date is null  or from_date = '' or from_date <= '{0}') 
+	conditions = ["""(from_date is null  or from_date = '' or from_date <= '{0}')
 		and (to_date is null  or to_date = '' or to_date >= '{0}')""".format(posting_date)]
 
 	for key, value in args.iteritems():
-		if key in "use_for_shopping_cart":
+		if key=="use_for_shopping_cart":
 			conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0))
 		else:
 			conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.json b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.json
index 897dec5..691a5c3 100644
--- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.json
+++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.json
@@ -7,12 +7,12 @@
  "doctype": "Report", 
  "idx": 1, 
  "is_standard": "Yes", 
- "modified": "2016-04-01 08:27:10.765516", 
+ "modified": "2016-04-04 17:27:19.104519", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Delivered Items To Be Billed", 
  "owner": "Administrator", 
- "query": "select\n    `tabDelivery Note`.`name` as \"Delivery Note:Link/Delivery Note:120\",\n\t`tabDelivery Note`.`customer` as \"Customer:Link/Customer:120\",\n\t`tabDelivery Note`.`posting_date` as \"Date:Date\",\n\t`tabDelivery Note`.`project` as \"Project\",\n\t`tabDelivery Note Item`.`item_code` as \"Item:Link/Item:120\",\n\t(`tabDelivery Note Item`.`qty` - ifnull((select sum(qty) from `tabSales Invoice Item` \n\t    where `tabSales Invoice Item`.docstatus=1 and \n            `tabSales Invoice Item`.delivery_note = `tabDelivery Note`.name and\n\t        `tabSales Invoice Item`.dn_detail = `tabDelivery Note Item`.name), 0))\n\t\tas \"Qty:Float:110\",\n\t(`tabDelivery Note Item`.`base_amount` - ifnull((select sum(base_amount) from `tabSales Invoice Item` \n        where `tabSales Invoice Item`.docstatus=1 and \n            `tabSales Invoice Item`.delivery_note = `tabDelivery Note`.name and\n            `tabSales Invoice Item`.dn_detail = `tabDelivery Note Item`.name), 0))\n\t\tas \"Amount:Currency:110\",\n\t`tabDelivery Note Item`.`item_name` as \"Item Name::150\",\n\t`tabDelivery Note Item`.`description` as \"Description::200\",\n\t`tabDelivery Note`.`company` as \"Company:Link/Company:\"\nfrom `tabDelivery Note`, `tabDelivery Note Item`\nwhere\n    `tabDelivery Note`.docstatus = 1 and\n\t`tabDelivery Note`.`status` not in (\"Stopped\", \"Closed\") and\n    `tabDelivery Note`.name = `tabDelivery Note Item`.parent and\n    (`tabDelivery Note Item`.qty > ifnull((select sum(qty) from `tabSales Invoice Item` \n        where `tabSales Invoice Item`.docstatus=1 and \n            `tabSales Invoice Item`.delivery_note = `tabDelivery Note`.name and\n            `tabSales Invoice Item`.dn_detail = `tabDelivery Note Item`.name), 0))\norder by `tabDelivery Note`.`name` desc", 
+ "query": "select\n    `tabDelivery Note`.`name` as \"Delivery Note:Link/Delivery Note:120\",\n\t`tabDelivery Note`.`customer` as \"Customer:Link/Customer:120\",\n\t`tabDelivery Note`.`posting_date` as \"Date:Date\",\n\t`tabDelivery Note`.`project` as \"Project\",\n\t`tabDelivery Note Item`.`item_code` as \"Item:Link/Item:120\",\n\t`tabDelivery Note Item`.`billed_amt` as \"Pending Amount:Currency:110\",\n\t`tabDelivery Note Item`.`item_name` as \"Item Name::150\",\n\t`tabDelivery Note Item`.`description` as \"Description::200\",\n\t`tabDelivery Note`.`company` as \"Company:Link/Company:\"\nfrom `tabDelivery Note`, `tabDelivery Note Item`\nwhere\n    `tabDelivery Note`.docstatus = 1 and\n\t`tabDelivery Note`.`status` not in (\"Stopped\", \"Closed\") and\n    `tabDelivery Note`.name = `tabDelivery Note Item`.parent and\n    `tabDelivery Note`.per_billed < 100\norder by `tabDelivery Note`.`name` desc", 
  "ref_doctype": "Sales Invoice", 
  "report_name": "Delivered Items To Be Billed", 
  "report_type": "Query Report"
diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.json b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.json
index e803a91..c38a7bb 100644
--- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.json
+++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.json
@@ -7,12 +7,12 @@
  "doctype": "Report", 
  "idx": 1, 
  "is_standard": "Yes", 
- "modified": "2016-04-01 08:27:07.033939", 
+ "modified": "2016-04-04 17:27:29.449124", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Received Items To Be Billed", 
  "owner": "Administrator", 
- "query": "select\n    `tabPurchase Receipt`.`name` as \"Purchase Receipt:Link/Purchase Receipt:120\",\n    `tabPurchase Receipt`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Receipt`.`posting_date` as \"Date:Date\",\n\t`tabPurchase Receipt Item`.`project` as \"Project\",\n\t`tabPurchase Receipt Item`.`item_code` as \"Item:Link/Item:120\",\n\t(`tabPurchase Receipt Item`.`qty` - ifnull((select sum(qty) from `tabPurchase Invoice Item` \n\t    where `tabPurchase Invoice Item`.purchase_receipt = `tabPurchase Receipt`.name and\n            `tabPurchase Invoice Item`.docstatus = 1 and\n\t    `tabPurchase Invoice Item`.pr_detail = `tabPurchase Receipt Item`.name), 0))\n\t    as \"Qty:Float:110\",\n\t(`tabPurchase Receipt Item`.`base_amount` - ifnull((select sum(base_amount) \n             from `tabPurchase Invoice Item` \n             where `tabPurchase Invoice Item`.purchase_receipt = `tabPurchase Receipt`.name and\n            `tabPurchase Invoice Item`.docstatus = 1 and\n            `tabPurchase Invoice Item`.pr_detail = `tabPurchase Receipt Item`.name), 0))\n\t    as \"Amount:Currency:110\",\n\t`tabPurchase Receipt Item`.`item_name` as \"Item Name::150\",\n\t`tabPurchase Receipt Item`.`description` as \"Description::200\",\n\t`tabPurchase Receipt`.`company` as \"Company:Link/Company:\"\nfrom `tabPurchase Receipt`, `tabPurchase Receipt Item`\nwhere\n    `tabPurchase Receipt`.docstatus = 1 and `tabPurchase Receipt`.status != \"Closed\" and \n    `tabPurchase Receipt`.name = `tabPurchase Receipt Item`.parent and\n    (`tabPurchase Receipt Item`.qty > ifnull((select sum(qty) from `tabPurchase Invoice Item` \n        where `tabPurchase Invoice Item`.purchase_receipt = `tabPurchase Receipt`.name and\n            `tabPurchase Invoice Item`.docstatus=1 and \n            `tabPurchase Invoice Item`.pr_detail = `tabPurchase Receipt Item`.name), 0))\norder by `tabPurchase Receipt`.`name` desc", 
+ "query": "select\n    `tabPurchase Receipt`.`name` as \"Purchase Receipt:Link/Purchase Receipt:120\",\n    `tabPurchase Receipt`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Receipt`.`posting_date` as \"Date:Date\",\n\t`tabPurchase Receipt Item`.`project` as \"Project\",\n\t`tabPurchase Receipt Item`.`item_code` as \"Item:Link/Item:120\",\n\t`tabPurchase Receipt Item`.`billed_amt` as \"Pending Amount:Currency:110\",\n\t`tabPurchase Receipt Item`.`item_name` as \"Item Name::150\",\n\t`tabPurchase Receipt Item`.`description` as \"Description::200\",\n\t`tabPurchase Receipt`.`company` as \"Company:Link/Company:\"\nfrom `tabPurchase Receipt`, `tabPurchase Receipt Item`\nwhere\n    `tabPurchase Receipt`.docstatus = 1 and `tabPurchase Receipt`.status != \"Closed\" and \n    `tabPurchase Receipt`.name = `tabPurchase Receipt Item`.parent and\n    `tabPurchase Receipt`.per_billed < 100\norder by `tabPurchase Receipt`.`name` desc", 
  "ref_doctype": "Purchase Invoice", 
  "report_name": "Received Items To Be Billed", 
  "report_type": "Query Report"
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index fd54dd7..cf418f6 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -7,7 +7,7 @@
 app_description = """ERP made simple"""
 app_icon = "icon-th"
 app_color = "#e74c3c"
-app_version = "6.27.5"
+app_version = "6.27.7"
 app_email = "info@erpnext.com"
 app_license = "GNU General Public License (v3)"
 source_link = "https://github.com/frappe/erpnext"
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 6740c6e..331a82b 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -77,7 +77,9 @@
 			frappe.throw(_("Total leaves allocated is mandatory"))
 
 	def validate_total_leaves_allocated(self):
-		if date_diff(self.to_date, self.from_date) <= flt(self.total_leaves_allocated):
+		# Adding a day to include To Date in the difference
+		date_difference = date_diff(self.to_date, self.from_date) + 1
+		if date_difference < self.total_leaves_allocated:
 			frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
 			
 	def validate_against_leave_applications(self):
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index f9f7377..63147d5 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -4,10 +4,11 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import add_days, cint, cstr, flt, getdate, nowdate, rounded, date_diff
+from frappe.utils import add_days, cint, cstr, flt, getdate, nowdate, rounded, date_diff, money_in_words
 from frappe.model.naming import make_autoname
 
 from frappe import msgprint, _
+from erpnext.accounts.utils import get_fiscal_year
 from erpnext.setup.utils import get_company_currency
 from erpnext.hr.utils import set_employee_name
 from erpnext.hr.doctype.process_payroll.process_payroll import get_month_details
@@ -18,6 +19,22 @@
 	def autoname(self):
 		self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
 
+	def validate(self):
+		self.check_existing()
+
+		if not (len(self.get("earnings")) or len(self.get("deductions"))):
+			self.get_emp_and_leave_details()
+		else:
+			self.get_leave_details(lwp = self.leave_without_pay)
+
+		if not self.net_pay:
+			self.calculate_net_pay()
+
+		company_currency = get_company_currency(self.company)
+		self.total_in_words = money_in_words(self.rounded_total, company_currency)
+
+		set_employee_name(self)
+
 	def get_emp_and_leave_details(self):
 		if self.employee:
 			joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
@@ -59,7 +76,9 @@
 
 	def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None):
 		if not self.fiscal_year:
-			self.fiscal_year = frappe.db.get_default("fiscal_year")
+			# if default fiscal year is not set, get from nowdate
+			self.fiscal_year = get_fiscal_year(nowdate())[0]
+
 		if not self.month:
 			self.month = "%02d" % getdate(nowdate()).month
 
@@ -150,23 +169,6 @@
 			self.employee = ''
 			frappe.throw(_("Salary Slip of employee {0} already created for this month").format(self.employee))
 
-	def validate(self):
-		from frappe.utils import money_in_words
-		self.check_existing()
-
-		if not (len(self.get("earnings")) or len(self.get("deductions"))):
-			self.get_emp_and_leave_details()
-		else:
-			self.get_leave_details(lwp = self.leave_without_pay)
-
-		if not self.net_pay:
-			self.calculate_net_pay()
-
-		company_currency = get_company_currency(self.company)
-		self.total_in_words = money_in_words(self.rounded_total, company_currency)
-
-		set_employee_name(self)
-
 	def calculate_earning_total(self):
 		self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount)
 		for d in self.get("earnings"):
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index efcceb3..1b9cbe5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -257,4 +257,5 @@
 execute:frappe.delete_doc_if_exists("Web Form", "contact") #2016-03-10
 erpnext.patches.v6_20x.remove_fiscal_year_from_holiday_list
 erpnext.patches.v6_24.map_customer_address_to_shipping_address_on_po
-erpnext.patches.v6_27.fix_recurring_order_status
\ No newline at end of file
+erpnext.patches.v6_27.fix_recurring_order_status
+erpnext.patches.v6_20x.update_product_bundle_description
diff --git a/erpnext/patches/v6_20x/update_product_bundle_description.py b/erpnext/patches/v6_20x/update_product_bundle_description.py
new file mode 100644
index 0000000..1fac44b
--- /dev/null
+++ b/erpnext/patches/v6_20x/update_product_bundle_description.py
@@ -0,0 +1,11 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import sanitize_html
+
+def execute():
+	for product_bundle in frappe.get_all('Product Bundle'):
+		doc = frappe.get_doc('Product Bundle', product_bundle.name)
+		for item in doc.items:
+			if item.description:
+				description = sanitize_html(item.description)
+				item.db_set('description', description, update_modified=False)
diff --git a/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html b/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
index 5fe7a14..fe8a963 100644
--- a/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
+++ b/erpnext/setup/page/welcome_to_erpnext/welcome_to_erpnext.html
@@ -21,7 +21,7 @@
 			<h3>{%= __("Next Steps") %}</h3>
 			<ul class="list-unstyled">
 				<li><a class="text-muted" href="#">{%= __("Go to the Desktop and start using ERPNext") %}</a></li>
-				<li><a class="text-muted" href="#Module/Learn">{%= __("View a list of all the help videos") %}</a></li>
+				<li><a class="text-muted" href="#modules/Learn">{%= __("View a list of all the help videos") %}</a></li>
 				<li><a class="text-muted" href="https://manual.erpnext.com" target="_blank">{%= __("Read the ERPNext Manual") %}</a></li>
 				<li><a class="text-muted" href="https://discuss.erpnext.com" target="_blank">{%= __("Community Forum") %}</a></li>
 			</ul>
diff --git a/setup.py b/setup.py
index 581e065..ac55dce 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
 from setuptools import setup, find_packages
 from pip.req import parse_requirements
 
-version = "6.27.5"
+version = "6.27.7"
 requirements = parse_requirements("requirements.txt", session="")
 
 setup(
diff --git a/travis/bench_init.sh b/travis/bench_init.sh
new file mode 100755
index 0000000..a8bb492
--- /dev/null
+++ b/travis/bench_init.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+cd ~/
+curl -I https://github.com/frappe/frappe/tree/$TRAVIS_BRANCH | head -n 1 | cut -d $' ' -f2 | (
+	read response;
+	[ $response == '200' ] && branch=$TRAVIS_BRANCH || branch='develop';
+	bench init frappe-bench --frappe-path https://github.com/frappe/frappe.git --frappe-branch $branch
+)