[Resolved] merge conflicts
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index d234e1e..90e5821 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.46'
+__version__ = '10.1.47'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/hr/doctype/employee_loan/employee_loan.js b/erpnext/hr/doctype/employee_loan/employee_loan.js
new file mode 100644
index 0000000..e089e29
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan/employee_loan.js
@@ -0,0 +1,121 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Loan', {
+	onload: function (frm) {
+		frm.set_query("employee_loan_application", function () {
+			return {
+				"filters": {
+					"employee": frm.doc.employee,
+					"docstatus": 1,
+					"status": "Approved"
+				}
+			};
+		});
+
+		frm.set_query("interest_income_account", function () {
+			return {
+				"filters": {
+					"company": frm.doc.company,
+					"root_type": "Income",
+					"is_group": 0
+				}
+			};
+		});
+
+		frm.set_query("employee", function() {
+			return {
+				"filters": {
+					"company": frm.doc.company,
+				}
+			};
+		});
+
+		$.each(["payment_account", "employee_loan_account"], function (i, field) {
+			frm.set_query(field, function () {
+				return {
+					"filters": {
+						"company": frm.doc.company,
+						"root_type": "Asset",
+						"is_group": 0
+					}
+				};
+			});
+		})
+	},
+
+	refresh: function (frm) {
+		if (frm.doc.docstatus == 1 && (frm.doc.status == "Sanctioned" || frm.doc.status == "Partially Disbursed")) {
+			frm.add_custom_button(__('Make Disbursement Entry'), function () {
+				frm.trigger("make_jv");
+			})
+		}
+		frm.trigger("toggle_fields");
+	},
+
+	make_jv: function (frm) {
+		frappe.call({
+			args: {
+				"employee_loan": frm.doc.name,
+				"company": frm.doc.company,
+				"employee_loan_account": frm.doc.employee_loan_account,
+				"employee": frm.doc.employee,
+				"loan_amount": frm.doc.loan_amount,
+				"payment_account": frm.doc.payment_account
+			},
+			method: "erpnext.hr.doctype.employee_loan.employee_loan.make_jv_entry",
+			callback: function (r) {
+				if (r.message)
+					var doc = frappe.model.sync(r.message)[0];
+				frappe.set_route("Form", doc.doctype, doc.name);
+			}
+		})
+	},
+
+	mode_of_payment: function (frm) {
+		if (frm.doc.mode_of_payment && frm.doc.company) {
+			frappe.call({
+				method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_bank_cash_account",
+				args: {
+					"mode_of_payment": frm.doc.mode_of_payment,
+					"company": frm.doc.company
+				},
+				callback: function (r, rt) {
+					if (r.message) {
+						frm.set_value("payment_account", r.message.account);
+					}
+				}
+			});
+		}
+	},
+
+	employee_loan_application: function (frm) {
+	    if(frm.doc.employee_loan_application){
+            return frappe.call({
+                method: "erpnext.hr.doctype.employee_loan.employee_loan.get_employee_loan_application",
+                args: {
+                    "employee_loan_application": frm.doc.employee_loan_application
+                },
+                callback: function (r) {
+                    if (!r.exc && r.message) {
+                        frm.set_value("loan_type", r.message.loan_type);
+                        frm.set_value("loan_amount", r.message.loan_amount);
+                        frm.set_value("repayment_method", r.message.repayment_method);
+                        frm.set_value("monthly_repayment_amount", r.message.repayment_amount);
+                        frm.set_value("repayment_periods", r.message.repayment_periods);
+                        frm.set_value("rate_of_interest", r.message.rate_of_interest);
+                    }
+                }
+            });
+        }
+	},
+
+	repayment_method: function (frm) {
+		frm.trigger("toggle_fields")
+	},
+
+	toggle_fields: function (frm) {
+		frm.toggle_enable("monthly_repayment_amount", frm.doc.repayment_method == "Repay Fixed Amount per Period")
+		frm.toggle_enable("repayment_periods", frm.doc.repayment_method == "Repay Over Number of Periods")
+	}
+});
diff --git a/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py
new file mode 100644
index 0000000..b6c6502
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, math
+from frappe import _
+from frappe.utils import flt, rounded
+from frappe.model.mapper import get_mapped_doc
+from frappe.model.document import Document
+
+from erpnext.hr.doctype.employee_loan.employee_loan import get_monthly_repayment_amount, check_repayment_method
+
+class EmployeeLoanApplication(Document):
+	def validate(self):
+		check_repayment_method(self.repayment_method, self.loan_amount, self.repayment_amount, self.repayment_periods)
+		self.validate_loan_amount()
+		self.get_repayment_details()
+
+	def validate_loan_amount(self):
+		maximum_loan_limit = frappe.db.get_value('Loan Type', self.loan_type, 'maximum_loan_amount')
+		if maximum_loan_limit and self.loan_amount > maximum_loan_limit:
+			frappe.throw(_("Loan Amount cannot exceed Maximum Loan Amount of {0}").format(maximum_loan_limit))
+
+	def get_repayment_details(self):
+		if self.repayment_method == "Repay Over Number of Periods":
+			self.repayment_amount = get_monthly_repayment_amount(self.repayment_method, self.loan_amount, self.rate_of_interest, self.repayment_periods)
+
+		if self.repayment_method == "Repay Fixed Amount per Period":
+			monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
+			if monthly_interest_rate:
+				monthly_interest_amount = self.loan_amount * monthly_interest_rate
+				if monthly_interest_amount >= self.repayment_amount:
+					frappe.throw(_("Repayment amount {} should be greater than monthly interest amount {}").
+						format(self.repayment_amount, monthly_interest_amount))
+
+				self.repayment_periods = math.ceil((math.log(self.repayment_amount) - 
+					math.log(self.repayment_amount - (monthly_interest_amount))) /
+					(math.log(1 + monthly_interest_rate)))
+			else:
+				self.repayment_periods = self.loan_amount / self.repayment_amount
+
+		self.calculate_payable_amount()
+		
+	def calculate_payable_amount(self):
+		balance_amount = self.loan_amount
+		self.total_payable_amount = 0
+		self.total_payable_interest = 0
+
+		while(balance_amount > 0):
+			interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100))
+			balance_amount = rounded(balance_amount + interest_amount - self.repayment_amount)
+
+			self.total_payable_interest += interest_amount
+			
+		self.total_payable_amount = self.loan_amount + self.total_payable_interest
+		
+@frappe.whitelist()
+def make_employee_loan(source_name, target_doc = None):
+	doclist = get_mapped_doc("Employee Loan Application", source_name, {
+		"Employee Loan Application": {
+			"doctype": "Employee Loan",
+			"validation": {
+				"docstatus": ["=", 1]
+			}
+		}
+	}, target_doc)
+
+	return doclist
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 2383804..d4beec3 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -63,7 +63,6 @@
 		self.validate_weights()
 		self.sync_tasks()
 		self.tasks = []
-		self.load_tasks()
 		self.send_welcome_email()
 
 	def validate_project_name(self):
@@ -86,6 +85,9 @@
 
 	def sync_tasks(self):
 		"""sync tasks and remove table"""
+		if not hasattr(self, "deleted_task_list"):
+			self.set("deleted_task_list", [])
+
 		if self.flags.dont_sync_tasks: return
 		task_names = []
 
@@ -134,7 +136,7 @@
 
 		# delete
 		for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
-			frappe.delete_doc("Task", t.name)
+			self.deleted_task_list.append(t.name)
 
 	def update_costing_and_percentage_complete(self):
 		self.update_percent_complete()
@@ -143,8 +145,14 @@
 	def is_row_updated(self, row, existing_task_data):
 		if self.get("__islocal") or not existing_task_data: return True
 
+		project_task_custom_fields = frappe.get_all("Custom Field", {"dt": "Project Task"}, "fieldname")
+
 		d = existing_task_data.get(row.task_id)
 
+		for field in project_task_custom_fields:
+			if row.get(field) != d.get(field):
+				return True
+
 		if (d and (row.title != d.title or row.status != d.status
 			or getdate(row.start_date) != getdate(d.start_date) or getdate(row.end_date) != getdate(d.end_date)
 			or row.description != d.description or row.task_weight != d.task_weight)):
@@ -272,9 +280,19 @@
 				user.welcome_email_sent = 1
 
 	def on_update(self):
+		self.delete_task()
+		self.load_tasks()
 		self.update_costing_and_percentage_complete()
 		self.update_dependencies_on_duplicated_project()
 
+	def delete_task(self):
+		if not self.get('deleted_task_list'): return
+
+		for d in self.get('deleted_task_list'):
+			frappe.delete_doc("Task", d)
+
+		self.deleted_task_list = []
+
 	def update_dependencies_on_duplicated_project(self):
 		if self.flags.dont_sync_tasks: return
 		if not self.copied_from:
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 2822ae8..0ecf6e1 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -26,7 +26,8 @@
 			};
 		});
 
-		if (this.frm.doc.__islocal) {
+		if (this.frm.doc.__islocal
+			&& frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) {
 			this.frm.set_value("disable_rounded_total", cint(frappe.sys_defaults.disable_rounded_total));
 		}