Merge pull request #15701 from shreyashah115/item-stock

Add column for Item Name in Item Price Stock report
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index e9bdbf9..a81cc85 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '10.1.58'
+__version__ = '10.1.59'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 5fa0707..f3e85b2 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -123,7 +123,7 @@
 			"reference_doctype": "Payment Request",
 			"reference_docname": self.name,
 			"payer_email": self.email_to or frappe.session.user,
-			"payer_name": data.customer_name,
+			"payer_name": frappe.safe_decode(data.customer_name),
 			"order_id": self.name,
 			"currency": self.currency
 		})
diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index 39ad0d4..aa29907 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -440,6 +440,38 @@
   {
    "allow_bulk_edit": 0, 
    "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "generate_invoice_at_period_start", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Generate Invoice At Beginning Of Period", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
@@ -814,7 +846,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-08-21 16:15:44.533482", 
+ "modified": "2018-10-04 10:29:03.338893", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Subscription", 
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index fe39161..7fb6b7a 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -321,6 +321,23 @@
 
 		self.save()
 
+	@property
+	def is_postpaid_to_invoice(self):
+		return getdate(nowdate()) > getdate(self.current_invoice_end) or \
+			(getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and \
+			not self.has_outstanding_invoice()
+
+	@property
+	def is_prepaid_to_invoice(self):
+		if not self.generate_invoice_at_period_start:
+			return False
+
+		if self.is_new_subscription():
+			return True
+
+		# Check invoice dates and make sure it doesn't have outstanding invoices
+		return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
+
 	def process_for_active(self):
 		"""
 		Called by `process` if the status of the `Subscription` is 'Active'.
@@ -330,7 +347,7 @@
 		2. Change the `Subscription` status to 'Past Due Date'
 		3. Change the `Subscription` status to 'Cancelled'
 		"""
-		if getdate(nowdate()) > getdate(self.current_invoice_end) or (getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and not self.has_outstanding_invoice():
+		if self.is_postpaid_to_invoice or self.is_prepaid_to_invoice:
 			self.generate_invoice()
 			if self.current_invoice_is_past_due():
 				self.status = 'Past Due Date'
@@ -338,7 +355,7 @@
 		if self.current_invoice_is_past_due() and getdate(nowdate()) > getdate(self.current_invoice_end):
 			self.status = 'Past Due Date'
 
-		if self.cancel_at_period_end and getdate(nowdate()) > self.current_invoice_end:
+		if self.cancel_at_period_end and getdate(nowdate()) > getdate(self.current_invoice_end):
 			self.cancel_subscription_at_period_end()
 
 	def cancel_subscription_at_period_end(self):
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index c42b8e8..a5285ea 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -500,3 +500,51 @@
 		self.assertEqual(invoice.apply_discount_on, 'Grand Total')
 
 		subscription.delete()
+
+	def test_prepaid_subscriptions(self):
+		# Create a non pre-billed subscription, processing should not create
+		# invoices.
+		subscription = frappe.new_doc('Subscription')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
+		subscription.save()
+		subscription.process()
+
+		self.assertEqual(len(subscription.invoices), 0)
+
+		# Change the subscription type to prebilled and process it.
+		# Prepaid invoice should be generated
+		subscription.generate_invoice_at_period_start = True
+		subscription.save()
+		subscription.process()
+
+		self.assertEqual(len(subscription.invoices), 1)
+
+	def test_prepaid_subscriptions_with_prorate_true(self):
+		settings = frappe.get_single('Subscription Settings')
+		to_prorate = settings.prorate
+		settings.prorate = 1
+		settings.save()
+
+		subscription = frappe.new_doc('Subscription')
+		subscription.subscriber = '_Test Customer'
+		subscription.generate_invoice_at_period_start = True
+		subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
+		subscription.save()
+		subscription.cancel_subscription()
+
+		self.assertEqual(len(subscription.invoices), 1)
+
+		current_inv = subscription.get_current_invoice()
+		self.assertEqual(current_inv.status, "Unpaid")
+
+		diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
+		plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
+		prorate_factor = flt(diff / plan_days)
+
+		self.assertEqual(flt(current_inv.grand_total, 2), flt(prorate_factor * 900, 2))
+
+		settings.prorate = to_prorate
+		settings.save()
+
+		subscription.delete()
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 40ec252..4573a42 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -167,7 +167,7 @@
 						<td style="text-align: right">
 							{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}</td>
 						<td style="text-align: right">
-							{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"])  %}</td>
+							{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["debit_note"], data[i]["currency"])  %}</td>
 					{% } %}
 					<td style="text-align: right">
 						{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}</td>
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index f54ff48..8b7ccaf 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -83,6 +83,7 @@
 			"{range3}-{above}".format(range3=cint(self.filters["range3"])+ 1, above=_("Above"))):
 				columns.append({
 					"label": label,
+					"fieldname":label,
 					"fieldtype": "Currency",
 					"options": "currency",
 					"width": 120
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
index 232d053..344539e 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js
@@ -8,6 +8,7 @@
 			"fieldname":"company",
 			"label": __("Company"),
 			"fieldtype": "Link",
+			"options": "Company",
 			"default": frappe.defaults.get_default('company')
 		},
 		{
diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
index 8e5723f..843b58f 100644
--- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
+++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py
@@ -64,13 +64,16 @@
 				total_amount_credited += k.credit
 
 		rate = [i.tax_withholding_rate for i in tds_doc.rates
-			if i.fiscal_year == gle_map[d][0].fiscal_year][0]
+			if i.fiscal_year == gle_map[d][0].fiscal_year]
 
-		if getdate(filters.from_date) <= gle_map[d][0].posting_date \
-			and getdate(filters.to_date) >= gle_map[d][0].posting_date:
-			out.append([supplier.pan, supplier.name, tds_doc.name,
-				supplier.supplier_type, rate, total_amount_credited, tds_deducted,
-				gle_map[d][0].posting_date, "Purchase Invoice", d])
+		if rate and len(rate) > 0:
+			rate = rate[0]
+
+			if getdate(filters.from_date) <= gle_map[d][0].posting_date \
+				and getdate(filters.to_date) >= gle_map[d][0].posting_date:
+				out.append([supplier.pan, supplier.name, tds_doc.name,
+					supplier.supplier_type, rate, total_amount_credited, tds_deducted,
+					gle_map[d][0].posting_date, "Purchase Invoice", d])
 
 	return out
 
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 696afb2..dbde304 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -69,7 +69,7 @@
 		# set contact and address details for supplier, if they are not mentioned
 		if getattr(self, "supplier", None):
 			self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions,
-			doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.shipping_address))
+			doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address')))
 
 		self.set_missing_item_details(for_validate)
 
diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json
index 95e7bfc..28e5351 100644
--- a/erpnext/healthcare/doctype/patient/patient.json
+++ b/erpnext/healthcare/doctype/patient/patient.json
@@ -1391,7 +1391,7 @@
  "issingle": 0,
  "istable": 0,
  "max_attachments": 50,
- "modified": "2018-10-09 22:09:39.849116",
+ "modified": "2018-10-14 22:09:39.849116",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Patient",
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index 7d948b8..5364031 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -339,13 +339,13 @@
 
 	data = frappe.db.sql("""select name, patient, practitioner, status,
 		duration, timestamp(appointment_date, appointment_time) as
-		'appointment_date' from `tabPatient Appointment` where
+		'start' from `tabPatient Appointment` where
 		(appointment_date between %(start)s and %(end)s)
 		and docstatus < 2 {conditions}""".format(conditions=conditions),
 		{"start": start, "end": end}, as_dict=True, update={"allDay": 0})
 
 	for item in data:
-		item.appointment_datetime = item.appointment_date + datetime.timedelta(minutes = item.duration)
+		item.end = item.start + datetime.timedelta(minutes = item.duration)
 
 	return data
 
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js
index fc674a8..2249d2a 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js
@@ -10,37 +10,5 @@
 	},
 	order_by: "appointment_date",
 	gantt: true,
-	get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events",
-	filters: [
-		{
-			'fieldtype': 'Link',
-			'fieldname': 'practitioner',
-			'options': 'Healthcare Practitioner',
-			'label': __('Healthcare Practitioner')
-		},
-		{
-			'fieldtype': 'Link',
-			'fieldname': 'patient',
-			'options': 'Patient',
-			'label': __('Patient')
-		},
-		{
-			'fieldtype': 'Link',
-			'fieldname': 'appointment_type',
-			'options': 'Appointment Type',
-			'label': __('Appointment Type')
-		},
-		{
-			'fieldtype': 'Link',
-			'fieldname': 'department',
-			'options': 'Medical Department',
-			'label': __('Department')
-		},
-		{
-			'fieldtype': 'Select',
-			'fieldname': 'status',
-			'options': 'Scheduled\nOpen\nClosed\nPending',
-			'label': __('Status')
-		}
-	]
+	get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events"
 };
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 250c5a6..b980d68 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -12,7 +12,7 @@
 source_link = "https://github.com/frappe/erpnext"
 
 develop_version = '11.x.x-develop'
-staging_version = '11.0.3-beta.10'
+staging_version = '11.0.3-beta.11'
 
 error_report_email = "support@erpnext.com"
 
diff --git a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
index 4aa3bbf..a404b5a 100644
--- a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
+++ b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py
@@ -9,6 +9,7 @@
 from email_reply_parser import EmailReplyParser
 from erpnext.hr.doctype.employee.employee import is_holiday
 from frappe.utils import global_date_format
+from six import string_types
 
 
 class DailyWorkSummary(Document):
@@ -108,7 +109,7 @@
 
 	:param group: Daily Work Summary Group `name`'''
 	group_doc = group
-	if isinstance(group_doc, str):
+	if isinstance(group_doc, string_types):
 		group_doc = frappe.get_doc('Daily Work Summary Group', group)
 
 	emails = [d.email for d in group_doc.users if frappe.db.get_value("User", d.user, "enabled")]
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 7285e04..cb4c190 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import getdate, validate_email_add, today, add_years
+from frappe.utils import getdate, validate_email_add, today, add_years, format_datetime
 from frappe.model.naming import set_name_by_naming_series
 from frappe import throw, _, scrub
 from frappe.permissions import add_user_permission, remove_user_permission, \
@@ -49,8 +49,7 @@
 			self.validate_onboarding_process()
 
 		if self.user_id:
-			self.validate_for_enabled_user_id()
-			self.validate_duplicate_user_id()
+			self.validate_user_details()
 		else:
 			existing_user_id = frappe.db.get_value("Employee", self.name, "user_id")
 			if existing_user_id:
@@ -60,6 +59,14 @@
 	def set_employee_name(self):
 		self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))
 
+	def validate_user_details(self):
+		data = frappe.db.get_value('User',
+			self.user_id, ['enabled', 'user_image'], as_dict=1)
+
+		self.image = data.get("user_image")
+		self.validate_for_enabled_user_id(data.get("enabled", 0))
+		self.validate_duplicate_user_id()
+
 	def update_nsm_model(self):
 		frappe.utils.nestedset.update_nsm(self)
 
@@ -143,10 +150,10 @@
 		if self.status == 'Left' and not self.relieving_date:
 			throw(_("Please enter relieving date."))
 
-	def validate_for_enabled_user_id(self):
+	def validate_for_enabled_user_id(self, enabled):
 		if not self.status == 'Active':
 			return
-		enabled = frappe.db.get_value("User", self.user_id, "enabled")
+
 		if enabled is None:
 			frappe.throw(_("User {0} does not exist").format(self.user_id))
 		if enabled == 0:
@@ -223,27 +230,63 @@
 	if int(frappe.db.get_single_value("HR Settings", "stop_birthday_reminders") or 0):
 		return
 
-	from frappe.utils.user import get_enabled_system_users
-	users = None
-
 	birthdays = get_employees_who_are_born_today()
 
 	if birthdays:
-		if not users:
-			users = [u.email_id or u.name for u in get_enabled_system_users()]
+		employee_list = frappe.get_all('Employee',
+			fields=['name','employee_name'],
+			filters={'status': 'Active',
+				'company': birthdays[0]['company']
+		 	}
+		)
+		employee_emails = get_employee_emails(employee_list)
+		birthday_names = [name["employee_name"] for name in birthdays]
+		birthday_emails = [email["user_id"] or email["personal_email"] or email["company_email"] for email in birthdays]
+
+		birthdays.append({'company_email': '','employee_name': '','personal_email': '','user_id': ''})
 
 		for e in birthdays:
-			frappe.sendmail(recipients=filter(lambda u: u not in (e.company_email, e.personal_email, e.user_id), users),
-				subject=_("Birthday Reminder for {0}").format(e.employee_name),
-				message=_("""Today is {0}'s birthday!""").format(e.employee_name),
-				reply_to=e.company_email or e.personal_email or e.user_id)
+			if e['company_email'] or e['personal_email'] or e['user_id']:
+				if len(birthday_names) == 1:
+					continue
+				recipients = e['company_email'] or e['personal_email'] or e['user_id']
+
+
+			else:
+				recipients = list(set(employee_emails) - set(birthday_emails))
+
+			frappe.sendmail(recipients=recipients,
+				subject=_("Birthday Reminder"),
+				message=get_birthday_reminder_message(e, birthday_names),
+				header=['Birthday Reminder', 'green'],
+			)
+
+def get_birthday_reminder_message(employee, employee_names):
+	"""Get employee birthday reminder message"""
+	pattern = "</Li><Br><Li>"
+	message = pattern.join(filter(lambda u: u not in (employee['employee_name']), employee_names))
+	message = message.title()
+
+	if pattern not in message:
+		message = "Today is {0}'s birthday \U0001F603".format(message)
+
+	else:
+		message = "Today your colleagues are celebrating their birthdays \U0001F382<br><ul><strong><li> " + message +"</li></strong></ul>"
+
+	return message
+
 
 def get_employees_who_are_born_today():
 	"""Get Employee properties whose birthday is today."""
-	return frappe.db.sql("""select name, personal_email, company_email, user_id, employee_name
-		from tabEmployee where day(date_of_birth) = day(%(date)s)
-		and month(date_of_birth) = month(%(date)s)
-		and status = 'Active'""", {"date": today()}, as_dict=True)
+	return frappe.db.get_values("Employee",
+		fieldname=["name", "personal_email", "company", "company_email", "user_id", "employee_name"],
+		filters={
+			"date_of_birth": ("like", "%{}".format(format_datetime(getdate(), "-MM-dd"))),
+			"status": "Active",
+		},
+		as_dict=True
+	)
+
 
 def get_holiday_list_for_employee(employee, raise_exception=True):
 	if employee:
@@ -319,10 +362,11 @@
 	for employee in employee_list:
 		if not employee:
 			continue
-		user, email = frappe.db.get_value('Employee', employee, ['user_id', 'company_email'])
-		if user or email:
-			employee_emails.append(user or email)
-
+		user, company_email, personal_email = frappe.db.get_value('Employee', employee,
+											['user_id', 'company_email', 'personal_email'])
+		email = user or company_email or personal_email
+		if email:
+			employee_emails.append(email)
 	return employee_emails
 
 @frappe.whitelist()
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index 72f4c54..1afb8f4 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -30,8 +30,7 @@
 		send_birthday_reminders()
 
 		email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
-		self.assertTrue("Subject: Birthday Reminder for {0}".format(employee.employee_name) \
-			in email_queue[0].message)
+		self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message)
 
 def make_employee(user):
 	if not frappe.db.get_value("User", user):
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 5cf9570..09cdd54 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -215,10 +215,11 @@
 			self.total_advance_amount += flt(d.allocated_amount)
 
 		if self.total_advance_amount:
-			if flt(self.total_advance_amount) > flt(self.total_claimed_amount):
+			precision = self.precision("total_advance_amount")
+			if flt(self.total_advance_amount, precision) > flt(self.total_claimed_amount, precision):
 				frappe.throw(_("Total advance amount cannot be greater than total claimed amount"))
 			if self.total_sanctioned_amount \
-					and flt(self.total_advance_amount) > flt(self.total_sanctioned_amount):
+					and flt(self.total_advance_amount, precision) > flt(self.total_sanctioned_amount, precision):
 				frappe.throw(_("Total advance amount cannot be greater than total sanctioned amount"))
 
 	def validate_sanctioned_amount(self):
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 77fc498..a55c3c5 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
  "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 0, 
@@ -479,6 +480,38 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "allow_same_item_multiple_times", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Allow Same Item Multiple Times", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "with_operations", 
    "fieldname": "transfer_material_against_job_card", 
    "fieldtype": "Check", 
@@ -1943,7 +1976,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-07-15 11:09:19.425998", 
+ "modified": "2018-10-11 11:52:39.047935", 
  "modified_by": "Administrator", 
  "module": "Manufacturing", 
  "name": "BOM", 
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 38e6156..b2c3e75 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -334,14 +334,15 @@
 				frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
 			check_list.append(m)
 
-		duplicate_items = list(get_duplicates(check_list))
-		if duplicate_items:
-			li = []
-			for i in duplicate_items:
-				li.append("{0} on row {1}".format(i.item_code, i.idx))
-			duplicate_list = '<br>' + '<br>'.join(li)
+		if not self.allow_same_item_multiple_times:
+			duplicate_items = list(get_duplicates(check_list))
+			if duplicate_items:
+				li = []
+				for i in duplicate_items:
+					li.append("{0} on row {1}".format(i.item_code, i.idx))
+				duplicate_list = '<br>' + '<br>'.join(li)
 
-			frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
+				frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
 
 	def check_recursion(self):
 		""" Check whether recursion occurs in any bom"""
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 26c3306..9c56948 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -571,3 +571,4 @@
 erpnext.patches.v11_0.ewaybill_fields_gst_india
 erpnext.patches.v11_0.drop_column_max_days_allowed
 erpnext.patches.v11_0.change_healthcare_desktop_icons
+erpnext.patches.v10_0.update_user_image_in_employee
diff --git a/erpnext/patches/v10_0/update_user_image_in_employee.py b/erpnext/patches/v10_0/update_user_image_in_employee.py
new file mode 100644
index 0000000..72d5d2a
--- /dev/null
+++ b/erpnext/patches/v10_0/update_user_image_in_employee.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	frappe.reload_doc('hr', 'doctype', 'employee')
+
+	frappe.db.sql("""
+		UPDATE
+			`tabEmployee`, `tabUser`
+		SET
+			`tabEmployee`.image = `tabUser`.user_image
+		WHERE
+			`tabEmployee`.user_id = `tabUser`.name and
+			`tabEmployee`.user_id is not null and
+			`tabEmployee`.user_id != '' and `tabEmployee`.image is null
+	""")
diff --git a/erpnext/patches/v11_0/change_healthcare_desktop_icons.py b/erpnext/patches/v11_0/change_healthcare_desktop_icons.py
index ab10c66..ed7df50 100644
--- a/erpnext/patches/v11_0/change_healthcare_desktop_icons.py
+++ b/erpnext/patches/v11_0/change_healthcare_desktop_icons.py
@@ -1,68 +1,93 @@
 import frappe
 from frappe import _
 
+change_icons_map = [
+	{
+		"module_name": "Patient",
+		"color": "#6BE273",
+		"icon": "fa fa-user",
+		"doctype": "Patient",
+		"type": "link",
+		"link": "List/Patient",
+		"label": _("Patient")
+	},
+	{
+		"module_name": "Patient Encounter",
+		"color": "#2ecc71",
+		"icon": "fa fa-stethoscope",
+		"doctype": "Patient Encounter",
+		"type": "link",
+		"link": "List/Patient Encounter",
+		"label": _("Patient Encounter"),
+	},
+	{
+		"module_name": "Healthcare Practitioner",
+		"color": "#2ecc71",
+		"icon": "fa fa-user-md",
+		"doctype": "Healthcare Practitioner",
+		"type": "link",
+		"link": "List/Healthcare Practitioner",
+		"label": _("Healthcare Practitioner")
+	},
+	{
+		"module_name": "Patient Appointment",
+		"color": "#934F92",
+		"icon": "fa fa-calendar-plus-o",
+		"doctype": "Patient Appointment",
+		"type": "link",
+		"link": "List/Patient Appointment",
+		"label": _("Patient Appointment")
+	},
+	{
+		"module_name": "Lab Test",
+		"color": "#7578f6",
+		"icon": "octicon octicon-beaker",
+		"doctype": "Lab Test",
+		"type": "link",
+		"link": "List/Lab Test",
+		"label": _("Lab Test")
+	}
+]
+
 def execute():
 	change_healthcare_desktop_icons()
 
 def change_healthcare_desktop_icons():
-	change_icons_map = [
-		{
-			"module_name": "Patient",
-			"color": "#6BE273",
-			"icon": "fa fa-user",
-			"doctype": "Patient",
-			"type": "link",
-			"link": "List/Patient",
-			"label": _("Patient")
-		},
-		{
-			"module_name": "Patient Encounter",
-			"color": "#2ecc71",
-			"icon": "fa fa-stethoscope",
-			"doctype": "Patient Encounter",
-			"type": "link",
-			"link": "List/Patient Encounter",
-			"label": _("Patient Encounter"),
-		},
-		{
-			"module_name": "Healthcare Practitioner",
-			"color": "#2ecc71",
-			"icon": "fa fa-user-md",
-			"doctype": "Healthcare Practitioner",
-			"type": "link",
-			"link": "List/Healthcare Practitioner",
-			"label": _("Healthcare Practitioner")
-		},
-		{
-			"module_name": "Patient Appointment",
-			"color": "#934F92",
-			"icon": "fa fa-calendar-plus-o",
-			"doctype": "Patient Appointment",
-			"type": "link",
-			"link": "List/Patient Appointment",
-			"label": _("Patient Appointment")
-		},
-		{
-			"module_name": "Lab Test",
-			"color": "#7578f6",
-			"icon": "octicon octicon-beaker",
-			"doctype": "Lab Test",
-			"type": "link",
-			"link": "List/Lab Test",
-			"label": _("Lab Test")
-		}
-	]
-
+	doctypes = ["patient", "patient_encounter", "healthcare_practitioner",
+		"patient_appointment", "lab_test"]
+	for doctype in doctypes:
+		frappe.reload_doc("healthcare", "doctype", doctype)
 	for spec in change_icons_map:
 		frappe.db.sql("""
-			update `tabDesktop Icon`
-			set module_name = '{0}', color = '{1}', icon = '{2}', _doctype = '{3}', type = '{4}',
-			link = '{5}', label = '{6}'
-			where _doctype = '{7}'
-		""".format(spec['module_name'], spec['color'], spec['icon'], spec['doctype'], spec['type'], spec['link'], spec['label'], spec['doctype']))
+			delete from `tabDesktop Icon`
+			where _doctype = '{0}'
+		""".format(spec['doctype']))
+
+		desktop_icon = frappe.new_doc("Desktop Icon")
+		desktop_icon.hidden = 1
+		desktop_icon.standard = 1
+		desktop_icon.icon = spec['icon']
+		desktop_icon.color = spec['color']
+		desktop_icon.module_name = spec['module_name']
+		desktop_icon.label = spec['label']
+		desktop_icon.app = "erpnext"
+		desktop_icon.type = spec['type']
+		desktop_icon._doctype = spec['doctype']
+		desktop_icon.link = spec['link']
+		desktop_icon.save(ignore_permissions=True)
 
 	frappe.db.sql("""
-		update `tabDesktop Icon`
-		set color = '#FF888B', icon = 'fa fa-heartbeat'
+		delete from `tabDesktop Icon`
 		where module_name = 'Healthcare' and type = 'module'
 	""")
+
+	desktop_icon = frappe.new_doc("Desktop Icon")
+	desktop_icon.hidden = 1
+	desktop_icon.standard = 1
+	desktop_icon.icon = "fa fa-heartbeat"
+	desktop_icon.color = "#FF888B"
+	desktop_icon.module_name = "Healthcare"
+	desktop_icon.label = _("Healthcare")
+	desktop_icon.app = "erpnext"
+	desktop_icon.type = 'module'
+	desktop_icon.save(ignore_permissions=True)
diff --git a/erpnext/patches/v11_0/refactor_naming_series.py b/erpnext/patches/v11_0/refactor_naming_series.py
index 1e4a53c..b85ab66 100644
--- a/erpnext/patches/v11_0/refactor_naming_series.py
+++ b/erpnext/patches/v11_0/refactor_naming_series.py
@@ -106,6 +106,8 @@
 			continue
 		if not frappe.db.has_column(doctype, 'naming_series'):
 			continue
+		if not frappe.get_meta(doctype).has_field('naming_series'):
+			continue
 		series_to_preserve = list(filter(None, get_series_to_preserve(doctype)))
 		default_series = get_default_series(doctype)
 
@@ -128,5 +130,6 @@
 	return series_to_preserve
 
 def get_default_series(doctype):
-	default_series = (frappe.get_meta(doctype).get_field("naming_series").default or "")
+	field = frappe.get_meta(doctype).get_field("naming_series")
+	default_series = field.get('default', '') if field else ''
 	return default_series
\ No newline at end of file
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py"
index a072ed0..5fbf700 100644
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py"
+++ "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.py"
@@ -105,9 +105,12 @@
 
 	for d in data:
 
-		JournalCode = re.split("-|/", d.get("voucher_no"))[0]
+		JournalCode = re.split("-|/|[0-9]", d.get("voucher_no"))[0]
 
-		EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
+		if d.get("voucher_no").startswith("{0}-".format(JournalCode)) or d.get("voucher_no").startswith("{0}/".format(JournalCode)):
+			EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
+		else:
+			EcritureNum = re.search("{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
 
 		EcritureDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
 
diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
index 8897792..180fd09 100644
--- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
+++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
@@ -5,6 +5,7 @@
 import frappe
 from frappe import msgprint, _
 from frappe.utils import flt
+from erpnext import get_company_currency
 
 def execute(filters=None):
 	if not filters: filters = {}
@@ -14,12 +15,14 @@
 	item_details = get_item_details()
 	data = []
 
+	company_currency = get_company_currency(filters["company"])
+
 	for d in entries:
 		if d.stock_qty > 0 or filters.get('show_return_entries', 0):
 			data.append([
 				d.name, d.customer, d.territory, item_details.get(d.item_code, {}).get("website_warehouse"), d.posting_date, d.item_code,
 				item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
-				d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
+				d.stock_qty, d.base_net_amount, d.sales_person, d.allocated_percentage, d.contribution_amt, company_currency
 			])
 
 	if data:
@@ -32,13 +35,105 @@
 	if not filters.get("doc_type"):
 		msgprint(_("Please select the document type first"), raise_exception=1)
 
-	return [filters["doc_type"] + ":Link/" + filters["doc_type"] + ":140",
-		_("Customer") + ":Link/Customer:140", _("Territory") + ":Link/Territory:100", _("Warehouse") + ":Link/Warehouse:100",
-		 _("Posting Date") + ":Date:100",
-		_("Item Code") + ":Link/Item:120", _("Item Group") + ":Link/Item Group:120",
-		_("Brand") + ":Link/Brand:120", _("Qty") + ":Float:100", _("Amount") + ":Currency:120",
-		_("Sales Person") + ":Link/Sales Person:140", _("Contribution %") + "::110",
-		_("Contribution Amount") + ":Currency:140"]
+	columns = [
+		{
+			"label": _(filters["doc_type"]),
+			"options": filters["doc_type"],
+			"fieldname": frappe.scrub(filters['doc_type']),
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Customer"),
+			"options": "Customer",
+			"fieldname": "customer",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Territory"),
+			"options": "Territory",
+			"fieldname": "territory",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Warehouse"),
+			"options": "Warehouse",
+			"fieldname": "warehouse",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Posting Date"),
+			"fieldname": "posting_date",
+			"fieldtype": "Date",
+			"width": 140
+		},
+		{
+			"label": _("Item Code"),
+			"options": "Item",
+			"fieldname": "item_code",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Item Group"),
+			"options": "Item Group",
+			"fieldname": "item_group",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Brand"),
+			"options": "Brand",
+			"fieldname": "brand",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Qty"),
+			"fieldname": "qty",
+			"fieldtype": "Float",
+			"width": 140
+		},
+		{
+			"label": _("Amount"),
+			"options": "currency",
+			"fieldname": "amount",
+			"fieldtype": "Currency",
+			"width": 140
+		},
+		{
+			"label": _("Sales Person"),
+			"options": "Sales Person",
+			"fieldname": "sales_person",
+			"fieldtype": "Link",
+			"width": 140
+		},
+		{
+			"label": _("Contribution %"),
+			"fieldname": "contribution",
+			"fieldtype": "Float",
+			"width": 140
+		},
+		{
+			"label": _("Contribution Amount"),
+			"options": "currency",
+			"fieldname": "contribution_amt",
+			"fieldtype": "Currency",
+			"width": 140
+		},
+		{
+			"label":_("Currency"),
+			"options": "Currency",
+			"fieldname":"currency",
+			"fieldtype":"Link",
+			"hidden" : 1
+		}
+	]
+
+	return columns
 
 def get_entries(filters):
 	date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index f32e959..17cf044 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -122,6 +122,7 @@
 		self.validate_fixed_asset()
 		self.validate_retain_sample()
 		self.validate_uom_conversion_factor()
+		self.validate_item_defaults()
 		self.update_defaults_from_item_group()
 
 		if not self.get("__islocal"):
@@ -663,6 +664,12 @@
 					template_item.flags.ignore_permissions = True
 					template_item.save()
 
+	def validate_item_defaults(self):
+		companies = list(set([row.company for row in self.item_defaults]))
+
+		if len(companies) != len(self.item_defaults):
+			frappe.throw(_("Cannot set multiple Item Defaults for a company."))
+
 	def update_defaults_from_item_group(self):
 		"""Get defaults from Item Group"""
 		if self.item_group and not self.item_defaults:
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 6ca3d5b..4845e0b 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -37,11 +37,18 @@
 			self._add_calendar_event(opts)
 
 	def delete_events(self):
-		events = frappe.db.sql_list("""select name from `tabEvent`
-			where ref_type=%s and ref_name=%s""", (self.doctype, self.name))
-		if events:
-			frappe.db.sql("delete from `tabEvent` where name in ({0})"
-				.format(", ".join(['%s']*len(events))), tuple(events))
+		participations = frappe.get_all("Event Participants", filters={"reference_doctype": self.doctype, "reference_docname": self.name,
+			"parenttype": "Event"}, fields=["name", "parent"])
+
+		if participations:
+			for participation in participations:
+				total_participants = frappe.get_all("Event Participants", filters={"parenttype": "Event", "parent": participation.parent})
+
+				if len(total_participants) <= 1:
+					frappe.db.sql("delete from `tabEvent` where name='%s'" % participation.parent)
+
+				frappe.db.sql("delete from `tabEvent Participants` where name='%s'" % participation.name)
+
 
 	def _add_calendar_event(self, opts):
 		opts = frappe._dict(opts)
@@ -54,11 +61,15 @@
 				"description": opts.description,
 				"starts_on":  self.contact_date,
 				"ends_on": opts.ends_on,
-				"event_type": "Private",
-				"ref_type": self.doctype,
-				"ref_name": self.name
+				"event_type": "Private"
 			})
 
+			event.append('event_participants', {
+				"reference_doctype": self.doctype,
+				"reference_docname": self.name
+				}
+			)
+
 			event.insert(ignore_permissions=True)
 
 			if frappe.db.exists("User", self.contact_by):