Merge branch 'develop' into payment-terms
diff --git a/.travis.yml b/.travis.yml
index 92c15e0..80d979f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,7 +56,6 @@
   - bench run-tests
   - sleep 5
   - bench reinstall --yes
-  - bench execute erpnext.setup.setup_wizard.utils.complete
-  - bench execute erpnext.setup.utils.enable_all_roles_and_domains
   - bench --verbose run-setup-wizard-ui-test
+  - bench execute erpnext.setup.utils.enable_all_roles_and_domains
   - bench run-ui-tests --app erpnext
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 12e46c4..dc37574 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -644,16 +644,9 @@
 		if(frm.doc.party) {
 			var party_amount = frm.doc.payment_type=="Receive" ?
 				frm.doc.paid_amount : frm.doc.received_amount;
-				
-			var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
-				function(d) { return flt(d.amount) }));
 
 			if(frm.doc.total_allocated_amount < party_amount) {
-				if(frm.doc.payment_type == "Receive") {
-					unallocated_amount = party_amount - (frm.doc.total_allocated_amount - total_deductions);
-				} else {
-					unallocated_amount = party_amount - (frm.doc.total_allocated_amount + total_deductions);
-				}
+				unallocated_amount = party_amount - frm.doc.total_allocated_amount;
 			}
 		}
 		frm.set_value("unallocated_amount", unallocated_amount);
@@ -672,11 +665,10 @@
 			difference_amount = flt(frm.doc.base_paid_amount) - flt(frm.doc.base_received_amount);
 		}
 
-		$.each(frm.doc.deductions || [], function(i, d) {
-			if(d.amount) difference_amount -= flt(d.amount);
-		})
+		var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
+			function(d) { return flt(d.amount) }));
 
-		frm.set_value("difference_amount", difference_amount);
+		frm.set_value("difference_amount", difference_amount - total_deductions);
 
 		frm.events.hide_unhide_fields(frm);
 	},
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index c6353d5..7ae9bde 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -281,13 +281,8 @@
 		if self.party:
 			party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
 
-			total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
-
 			if self.total_allocated_amount < party_amount:
-				if self.payment_type == "Receive":
-					self.unallocated_amount = party_amount - (self.total_allocated_amount - total_deductions)
-				else:
-					self.unallocated_amount = party_amount - (self.total_allocated_amount + total_deductions)
+				self.unallocated_amount = party_amount - self.total_allocated_amount
 
 	def set_difference_amount(self):
 		base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
@@ -302,11 +297,10 @@
 		else:
 			self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
 
-		for d in self.get("deductions"):
-			if d.amount:
-				self.difference_amount -= flt(d.amount)
+		total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
 
-		self.difference_amount = flt(self.difference_amount, self.precision("difference_amount"))
+		self.difference_amount = flt(self.difference_amount - total_deductions,
+			self.precision("difference_amount"))
 
 	def clear_unallocated_reference_document_rows(self):
 		self.set("references", self.get("references", {"allocated_amount": ["not in", [0, None, ""]]}))
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 0316cca..60be20d 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -267,3 +267,65 @@
 		return frappe.db.sql("""select account, debit, credit, against_voucher
 			from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
 			order by account asc""", voucher_no, as_dict=1)
+
+	def test_payment_entry_write_off_difference(self):
+		si =  create_sales_invoice()
+		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
+		pe.reference_no = "1"
+		pe.reference_date = "2016-01-01"
+		pe.received_amount = pe.paid_amount = 110
+		pe.insert()
+
+		self.assertEqual(pe.unallocated_amount, 10)
+
+		pe.received_amount = pe.paid_amount = 95
+		pe.append("deductions", {
+			"account": "_Test Write Off - _TC",
+			"cost_center": "_Test Cost Center - _TC",
+			"amount": 5
+		})
+		pe.save()
+
+		self.assertEqual(pe.unallocated_amount, 0)
+		self.assertEqual(pe.difference_amount, 0)
+
+		pe.submit()
+
+		expected_gle = dict((d[0], d) for d in [
+			["Debtors - _TC", 0, 100, si.name],
+			["_Test Cash - _TC", 95, 0, None],
+			["_Test Write Off - _TC", 5, 0, None]
+		])
+
+		self.validate_gl_entries(pe.name, expected_gle)
+
+	def test_payment_entry_exchange_gain_loss(self):
+		si =  create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+			currency="USD", conversion_rate=50)
+		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
+		pe.reference_no = "1"
+		pe.reference_date = "2016-01-01"
+		pe.target_exchange_rate = 55
+
+		pe.append("deductions", {
+			"account": "_Test Exchange Gain/Loss - _TC",
+			"cost_center": "_Test Cost Center - _TC",
+			"amount": -500
+		})
+		pe.save()
+
+		self.assertEqual(pe.unallocated_amount, 0)
+		self.assertEqual(pe.difference_amount, 0)
+
+		pe.submit()
+
+		expected_gle = dict((d[0], d) for d in [
+			["_Test Receivable USD - _TC", 0, 5000, si.name],
+			["_Test Bank USD - _TC", 5500, 0, None],
+			["_Test Exchange Gain/Loss - _TC", 0, 500, None],
+		])
+
+		self.validate_gl_entries(pe.name, expected_gle)
+
+		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
+		self.assertEqual(outstanding_amount, 0)
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js
new file mode 100644
index 0000000..7dea76d
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js
@@ -0,0 +1,51 @@
+QUnit.module('Payment Entry');
+
+QUnit.test("test payment entry", function(assert) {
+	assert.expect(6);
+	let done = assert.async();
+	frappe.run_serially([
+		() => {
+			return frappe.tests.make('Sales Invoice', [
+				{customer: 'Test Customer 1'},
+				{items: [
+					[
+						{'qty': 1},
+						{'rate': 101},
+						{'item_code': 'Test Product 1'},
+					]
+				]}
+			]);
+		},
+		() => cur_frm.save(),
+		() => frappe.tests.click_button('Submit'),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.click_button('Make'),
+		() => frappe.click_link('Payment', 1),
+		() => frappe.timeout(2),
+		() => {
+			assert.equal(frappe.get_route()[1], 'Payment Entry',
+				'made payment entry');
+			assert.equal(cur_frm.doc.party, 'Test Customer 1',
+				'customer set in payment entry');
+			assert.equal(cur_frm.doc.paid_amount, 101,
+				'paid amount set in payment entry');
+			assert.equal(cur_frm.doc.references[0].allocated_amount, 101,
+				'amount allocated against sales invoice');
+		},
+		() => cur_frm.set_value('paid_amount', 100),
+		() => {
+			cur_frm.doc.references[0].allocated_amount = 101;
+		},
+		() => frappe.click_button('Write Off Difference Amount'),
+		() => {
+			assert.equal(cur_frm.doc.difference_amount, 0,
+				'difference amount is zero');
+			assert.equal(cur_frm.doc.deductions[0].amount, 1,
+				'Write off amount = 1');
+		},
+		() => done()
+	]);
+});
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
index a4ef0ca..0c76343 100644
--- a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js
@@ -25,5 +25,4 @@
 		() => frappe.timeout(0.3),
 		() => done()
 	]);
-});
-
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js
new file mode 100644
index 0000000..133f136
--- /dev/null
+++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js
@@ -0,0 +1,67 @@
+QUnit.module('Payment Entry');
+
+QUnit.test("test payment entry", function(assert) {
+	assert.expect(8);
+	let done = assert.async();
+	frappe.run_serially([
+		() => {
+			return frappe.tests.make('Sales Invoice', [
+				{customer: 'Test Customer 1'},
+				{company: '_Test Company'},
+				{currency: 'INR'},
+				{selling_price_list: '_Test Price List'},
+				{items: [
+					[
+						{'qty': 1},
+						{'item_code': 'Test Product 1'},
+					]
+				]}
+			]);
+		},
+		() => frappe.timeout(1),
+		() => cur_frm.save(),
+		() => frappe.tests.click_button('Submit'),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(1.5),
+		() => frappe.click_button('Close'),
+		() => frappe.timeout(0.5),
+		() => frappe.click_button('Make'),
+		() => frappe.timeout(1),
+		() => frappe.click_link('Payment'),
+		() => frappe.timeout(2),
+		() => cur_frm.set_value("paid_to", "_Test Cash - _TC"),
+		() => frappe.timeout(0.5),
+		() => {
+			assert.equal(frappe.get_route()[1], 'Payment Entry', 'made payment entry');
+			assert.equal(cur_frm.doc.party, 'Test Customer 1', 'customer set in payment entry');
+			assert.equal(cur_frm.doc.paid_from, 'Debtors - _TC', 'customer account set in payment entry');
+			assert.equal(cur_frm.doc.paid_amount, 100, 'paid amount set in payment entry');
+			assert.equal(cur_frm.doc.references[0].allocated_amount, 100,
+				'amount allocated against sales invoice');
+		},
+		() => cur_frm.set_value('paid_amount', 95),
+		() => frappe.timeout(1),
+		() => {
+			frappe.model.set_value("Payment Entry Reference",
+				cur_frm.doc.references[0].name, "allocated_amount", 100);
+		},
+		() => frappe.timeout(.5),
+		() => {
+			assert.equal(cur_frm.doc.difference_amount, 5, 'difference amount is 5');
+		},
+		() => {
+			frappe.db.set_value("Company", "_Test Company", "write_off_account", "_Test Write Off - _TC");
+			frappe.timeout(1);
+			frappe.db.set_value("Company", "_Test Company",
+				"exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC");
+		},
+		() => frappe.timeout(1),
+		() => frappe.click_button('Write Off Difference Amount'),
+		() => frappe.timeout(2),
+		() => {
+			assert.equal(cur_frm.doc.difference_amount, 0, 'difference amount is zero');
+			assert.equal(cur_frm.doc.deductions[0].amount, 5, 'Write off amount = 5');
+		},
+		() => done()
+	]);
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/tests/test_training_event_attandance.js b/erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js
similarity index 100%
rename from erpnext/hr/doctype/training_event/tests/test_training_event_attandance.js
rename to erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
index 20a3bc5..b7eae38 100644
--- a/erpnext/hr/doctype/training_feedback/training_feedback.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -20,4 +20,4 @@
 				training_event.status = 'Feedback Submitted'
 				break
 
-		training_event.update_after_submit()
+		training_event.save()
diff --git a/erpnext/patches/v8_9/rename_company_sales_target_field.py b/erpnext/patches/v8_9/rename_company_sales_target_field.py
index 8c54283..5433eb6 100644
--- a/erpnext/patches/v8_9/rename_company_sales_target_field.py
+++ b/erpnext/patches/v8_9/rename_company_sales_target_field.py
@@ -4,4 +4,5 @@
 
 def execute():
 	frappe.reload_doc("setup", "doctype", "company")
-	rename_field("Company", "sales_target", "monthly_sales_target")
+	if frappe.db.has_column('Company', 'sales_target'):
+		rename_field("Company", "sales_target", "monthly_sales_target")
diff --git a/erpnext/setup/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py
index aed6698..2db63c1 100644
--- a/erpnext/setup/setup_wizard/test_setup_wizard.py
+++ b/erpnext/setup/setup_wizard/test_setup_wizard.py
@@ -9,12 +9,13 @@
 def run_setup_wizard_test():
 	driver = TestDriver()
 	frappe.db.set_default('in_selenium', '1')
+	frappe.db.commit()
 
 	driver.login('#page-setup-wizard')
 	print('Running Setup Wizard Test...')
 
 	# Language slide
-	driver.set_select("language", "English (United Kingdom)")
+	driver.set_select("language", "English (United States)")
 	driver.wait_for_ajax(True)
 	driver.wait_till_clickable(".next-btn").click()
 
@@ -25,9 +26,9 @@
 	driver.wait_till_clickable(".next-btn").click()
 
 	# Profile slide
-	driver.set_field("full_name", "Joe Davis")
-	driver.set_field("email", "joe@example.com")
-	driver.set_field("password", "somethingrandom")
+	driver.set_field("full_name", "Great Tester")
+	driver.set_field("email", "great@example.com")
+	driver.set_field("password", "test")
 	driver.wait_till_clickable(".next-btn").click()
 
 	# Brand slide
@@ -35,14 +36,14 @@
 	driver.wait_till_clickable(".next-btn").click()
 
 	# Org slide
-	driver.set_field("company_name", "Acme Corp")
+	driver.set_field("company_name", "For Testing")
 	driver.wait_till_clickable(".next-btn").click()
-	driver.set_field("company_tagline", "Build Tools for Builders")
-	driver.set_field("bank_account", "BNL")
+	driver.set_field("company_tagline", "Just for GST")
+	driver.set_field("bank_account", "HDFC")
 	driver.wait_till_clickable(".complete-btn").click()
 
-	# Wait for desk (Lock wait timeout error)
-	# driver.wait_for('#page-desktop', timeout=200)
+	# Wait for desktop
+	driver.wait_for('#page-desktop', timeout=600)
 
 	console = driver.get_console()
 	if frappe.flags.tests_verbose:
@@ -52,6 +53,8 @@
 	time.sleep(1)
 
 	frappe.db.set_default('in_selenium', None)
+	frappe.db.commit()
+
 	driver.close()
 
 	return True
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/utils.py b/erpnext/setup/setup_wizard/utils.py
index dc4abd4..d821a12 100644
--- a/erpnext/setup/setup_wizard/utils.py
+++ b/erpnext/setup/setup_wizard/utils.py
@@ -10,6 +10,3 @@
 
 	#setup_wizard.create_sales_tax(data)
 	setup_complete(data)
-
-
-
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 5dc97f6..f2ea1d8 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -488,6 +488,8 @@
 	def validate_warehouse_for_reorder(self):
 		warehouse = []
 		for i in self.get("reorder_levels"):
+			if not i.warehouse_group:
+				i.warehouse_group = i.warehouse
 			if i.get("warehouse") and i.get("warehouse") not in warehouse:
 				warehouse += [i.get("warehouse")]
 			else:
diff --git a/erpnext/templates/print_formats/includes/taxes.html b/erpnext/templates/print_formats/includes/taxes.html
index b180c1c..b782763 100644
--- a/erpnext/templates/print_formats/includes/taxes.html
+++ b/erpnext/templates/print_formats/includes/taxes.html
@@ -19,7 +19,7 @@
 		{%- for charge in data -%}
 			{%- if charge.tax_amount and not charge.included_in_print_rate -%}
 			<div class="row">
-				<div class="col-xs-5 {%- if not doc._align_labels_left %} text-right{%- endif -%}">
+				<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}">
 					<label>{{ charge.get_formatted("description") }}</label></div>
 				<div class="col-xs-7 text-right">
 					{{ frappe.format_value(frappe.utils.flt(charge.tax_amount),
diff --git a/erpnext/tests/ui/make_fixtures.js b/erpnext/tests/ui/make_fixtures.js
index 0c5b4be..f817c65 100644
--- a/erpnext/tests/ui/make_fixtures.js
+++ b/erpnext/tests/ui/make_fixtures.js
@@ -205,6 +205,18 @@
 			{title: "Test Term 2"}
 		]
 	},
+	"Item Price": {
+		"ITEM-PRICE-00001": [
+			{item_code: 'Test Product 1'},
+			{price_list: '_Test Price List'},
+			{price_list_rate: 100}
+		],
+		"ITEM-PRICE-00002": [
+			{item_code: 'Test Product 2'},
+			{price_list: '_Test Price List'},
+			{price_list_rate: 200}
+		]
+	}
 });
 
 
diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt
index 313554b..6017f6f 100644
--- a/erpnext/tests/ui/tests.txt
+++ b/erpnext/tests/ui/tests.txt
@@ -125,4 +125,5 @@
 erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js
 erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js
 erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js
-erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
\ No newline at end of file
+erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js
+erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js