Merge branch 'develop' into fix-job-opening
This commit is contained in:
		
						commit
						3f13b0ec97
					
				| @ -78,6 +78,8 @@ class TestPeriodClosingVoucher(unittest.TestCase): | |||||||
| 			expense_account="Cost of Goods Sold - TPC", | 			expense_account="Cost of Goods Sold - TPC", | ||||||
| 			rate=400, | 			rate=400, | ||||||
| 			debit_to="Debtors - TPC", | 			debit_to="Debtors - TPC", | ||||||
|  | 			currency="USD", | ||||||
|  | 			customer="_Test Customer USD", | ||||||
| 		) | 		) | ||||||
| 		create_sales_invoice( | 		create_sales_invoice( | ||||||
| 			company=company, | 			company=company, | ||||||
| @ -86,6 +88,8 @@ class TestPeriodClosingVoucher(unittest.TestCase): | |||||||
| 			expense_account="Cost of Goods Sold - TPC", | 			expense_account="Cost of Goods Sold - TPC", | ||||||
| 			rate=200, | 			rate=200, | ||||||
| 			debit_to="Debtors - TPC", | 			debit_to="Debtors - TPC", | ||||||
|  | 			currency="USD", | ||||||
|  | 			customer="_Test Customer USD", | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 		pcv = self.make_period_closing_voucher(submit=False) | 		pcv = self.make_period_closing_voucher(submit=False) | ||||||
| @ -119,14 +123,17 @@ class TestPeriodClosingVoucher(unittest.TestCase): | |||||||
| 		surplus_account = create_account() | 		surplus_account = create_account() | ||||||
| 		cost_center = create_cost_center("Test Cost Center 1") | 		cost_center = create_cost_center("Test Cost Center 1") | ||||||
| 
 | 
 | ||||||
| 		create_sales_invoice( | 		si = create_sales_invoice( | ||||||
| 			company=company, | 			company=company, | ||||||
| 			income_account="Sales - TPC", | 			income_account="Sales - TPC", | ||||||
| 			expense_account="Cost of Goods Sold - TPC", | 			expense_account="Cost of Goods Sold - TPC", | ||||||
| 			cost_center=cost_center, | 			cost_center=cost_center, | ||||||
| 			rate=400, | 			rate=400, | ||||||
| 			debit_to="Debtors - TPC", | 			debit_to="Debtors - TPC", | ||||||
|  | 			currency="USD", | ||||||
|  | 			customer="_Test Customer USD", | ||||||
| 		) | 		) | ||||||
|  | 
 | ||||||
| 		jv = make_journal_entry( | 		jv = make_journal_entry( | ||||||
| 			account1="Cash - TPC", | 			account1="Cash - TPC", | ||||||
| 			account2="Sales - TPC", | 			account2="Sales - TPC", | ||||||
|  | |||||||
| @ -752,7 +752,7 @@ class TestPricingRule(unittest.TestCase): | |||||||
| 			title="_Test Pricing Rule with Min Qty - 2", | 			title="_Test Pricing Rule with Min Qty - 2", | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 		si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1, currency="USD") | 		si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1) | ||||||
| 		item = si.items[0] | 		item = si.items[0] | ||||||
| 		item.stock_qty = 1 | 		item.stock_qty = 1 | ||||||
| 		si.save() | 		si.save() | ||||||
|  | |||||||
| @ -1,10 +1,12 @@ | |||||||
| { | { | ||||||
|  |  "actions": [], | ||||||
|  "allow_import": 1, |  "allow_import": 1, | ||||||
|  "allow_rename": 1, |  "allow_rename": 1, | ||||||
|  "creation": "2013-01-10 16:34:08", |  "creation": "2013-01-10 16:34:08", | ||||||
|  "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n    - This can be on **Net Total** (that is the sum of basic amount).\n    - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n    - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.", |  "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n    - This can be on **Net Total** (that is the sum of basic amount).\n    - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n    - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.", | ||||||
|  "doctype": "DocType", |  "doctype": "DocType", | ||||||
|  "document_type": "Setup", |  "document_type": "Setup", | ||||||
|  |  "engine": "InnoDB", | ||||||
|  "field_order": [ |  "field_order": [ | ||||||
|   "title", |   "title", | ||||||
|   "is_default", |   "is_default", | ||||||
| @ -74,7 +76,8 @@ | |||||||
|  ], |  ], | ||||||
|  "icon": "fa fa-money", |  "icon": "fa fa-money", | ||||||
|  "idx": 1, |  "idx": 1, | ||||||
|  "modified": "2019-11-25 13:05:26.220275", |  "links": [], | ||||||
|  |  "modified": "2022-05-16 16:15:29.059370", | ||||||
|  "modified_by": "Administrator", |  "modified_by": "Administrator", | ||||||
|  "module": "Accounts", |  "module": "Accounts", | ||||||
|  "name": "Purchase Taxes and Charges Template", |  "name": "Purchase Taxes and Charges Template", | ||||||
| @ -103,6 +106,10 @@ | |||||||
|    "role": "Purchase User" |    "role": "Purchase User" | ||||||
|   } |   } | ||||||
|  ], |  ], | ||||||
|  |  "show_title_field_in_link": 1, | ||||||
|  |  "sort_field": "modified", | ||||||
|  "sort_order": "DESC", |  "sort_order": "DESC", | ||||||
|  |  "states": [], | ||||||
|  |  "title_field": "title", | ||||||
|  "track_changes": 1 |  "track_changes": 1 | ||||||
| } | } | ||||||
| @ -861,27 +861,44 @@ frappe.ui.form.on('Sales Invoice', { | |||||||
| 
 | 
 | ||||||
| 	set_timesheet_data: function(frm, timesheets) { | 	set_timesheet_data: function(frm, timesheets) { | ||||||
| 		frm.clear_table("timesheets") | 		frm.clear_table("timesheets") | ||||||
| 		timesheets.forEach(timesheet => { | 		timesheets.forEach(async (timesheet) => { | ||||||
| 			if (frm.doc.currency != timesheet.currency) { | 			if (frm.doc.currency != timesheet.currency) { | ||||||
| 				frappe.call({ | 				const exchange_rate = await frm.events.get_exchange_rate( | ||||||
| 					method: "erpnext.setup.utils.get_exchange_rate", | 					frm, timesheet.currency, frm.doc.currency | ||||||
| 					args: { | 				) | ||||||
| 						from_currency: timesheet.currency, | 				frm.events.append_time_log(frm, timesheet, exchange_rate) | ||||||
| 						to_currency: frm.doc.currency |  | ||||||
| 					}, |  | ||||||
| 					callback: function(r) { |  | ||||||
| 						if (r.message) { |  | ||||||
| 							exchange_rate = r.message; |  | ||||||
| 							frm.events.append_time_log(frm, timesheet, exchange_rate); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				}); |  | ||||||
| 			} else { | 			} else { | ||||||
| 				frm.events.append_time_log(frm, timesheet, 1.0); | 				frm.events.append_time_log(frm, timesheet, 1.0); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | 	async get_exchange_rate(frm, from_currency, to_currency) { | ||||||
|  | 		if ( | ||||||
|  | 			frm.exchange_rates | ||||||
|  | 			&& frm.exchange_rates[from_currency] | ||||||
|  | 			&& frm.exchange_rates[from_currency][to_currency] | ||||||
|  | 		) { | ||||||
|  | 			return frm.exchange_rates[from_currency][to_currency]; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return frappe.call({ | ||||||
|  | 			method: "erpnext.setup.utils.get_exchange_rate", | ||||||
|  | 			args: { | ||||||
|  | 				from_currency, | ||||||
|  | 				to_currency | ||||||
|  | 			}, | ||||||
|  | 			callback: function(r) { | ||||||
|  | 				if (r.message) { | ||||||
|  | 					// cache exchange rates
 | ||||||
|  | 					frm.exchange_rates = frm.exchange_rates || {}; | ||||||
|  | 					frm.exchange_rates[from_currency] = frm.exchange_rates[from_currency] || {}; | ||||||
|  | 					frm.exchange_rates[from_currency][to_currency] = r.message; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
| 	append_time_log: function(frm, time_log, exchange_rate) { | 	append_time_log: function(frm, time_log, exchange_rate) { | ||||||
| 		const row = frm.add_child("timesheets"); | 		const row = frm.add_child("timesheets"); | ||||||
| 		row.activity_type = time_log.activity_type; | 		row.activity_type = time_log.activity_type; | ||||||
| @ -892,7 +909,7 @@ frappe.ui.form.on('Sales Invoice', { | |||||||
| 		row.billing_hours = time_log.billing_hours; | 		row.billing_hours = time_log.billing_hours; | ||||||
| 		row.billing_amount = flt(time_log.billing_amount) * flt(exchange_rate); | 		row.billing_amount = flt(time_log.billing_amount) * flt(exchange_rate); | ||||||
| 		row.timesheet_detail = time_log.name; | 		row.timesheet_detail = time_log.name; | ||||||
|     row.project_name = time_log.project_name; | 		row.project_name = time_log.project_name; | ||||||
| 
 | 
 | ||||||
| 		frm.refresh_field("timesheets"); | 		frm.refresh_field("timesheets"); | ||||||
| 		frm.trigger("calculate_timesheet_totals"); | 		frm.trigger("calculate_timesheet_totals"); | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| { | { | ||||||
|  |  "actions": [], | ||||||
|  "allow_import": 1, |  "allow_import": 1, | ||||||
|  "allow_rename": 1, |  "allow_rename": 1, | ||||||
|  "creation": "2013-01-10 16:34:09", |  "creation": "2013-01-10 16:34:09", | ||||||
| @ -77,7 +78,8 @@ | |||||||
|  ], |  ], | ||||||
|  "icon": "fa fa-money", |  "icon": "fa fa-money", | ||||||
|  "idx": 1, |  "idx": 1, | ||||||
|  "modified": "2019-11-25 13:06:03.279099", |  "links": [], | ||||||
|  |  "modified": "2022-05-16 16:14:52.061672", | ||||||
|  "modified_by": "Administrator", |  "modified_by": "Administrator", | ||||||
|  "module": "Accounts", |  "module": "Accounts", | ||||||
|  "name": "Sales Taxes and Charges Template", |  "name": "Sales Taxes and Charges Template", | ||||||
| @ -113,7 +115,10 @@ | |||||||
|    "write": 1 |    "write": 1 | ||||||
|   } |   } | ||||||
|  ], |  ], | ||||||
|  |  "show_title_field_in_link": 1, | ||||||
|  "sort_field": "modified", |  "sort_field": "modified", | ||||||
|  "sort_order": "ASC", |  "sort_order": "ASC", | ||||||
|  |  "states": [], | ||||||
|  |  "title_field": "title", | ||||||
|  "track_changes": 1 |  "track_changes": 1 | ||||||
| } | } | ||||||
| @ -897,3 +897,18 @@ def get_default_contact(doctype, name): | |||||||
| 			return None | 			return None | ||||||
| 	else: | 	else: | ||||||
| 		return None | 		return None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def add_party_account(party_type, party, company, account): | ||||||
|  | 	doc = frappe.get_doc(party_type, party) | ||||||
|  | 	account_exists = False | ||||||
|  | 	for d in doc.get("accounts"): | ||||||
|  | 		if d.account == account: | ||||||
|  | 			account_exists = True | ||||||
|  | 
 | ||||||
|  | 	if not account_exists: | ||||||
|  | 		accounts = {"company": company, "account": account} | ||||||
|  | 
 | ||||||
|  | 		doc.append("accounts", accounts) | ||||||
|  | 
 | ||||||
|  | 		doc.save() | ||||||
|  | |||||||
| @ -198,10 +198,12 @@ def get_loan_entries(filters): | |||||||
| 			amount_field = (loan_doc.disbursed_amount).as_("credit") | 			amount_field = (loan_doc.disbursed_amount).as_("credit") | ||||||
| 			posting_date = (loan_doc.disbursement_date).as_("posting_date") | 			posting_date = (loan_doc.disbursement_date).as_("posting_date") | ||||||
| 			account = loan_doc.disbursement_account | 			account = loan_doc.disbursement_account | ||||||
|  | 			salary_condition = loan_doc.docstatus == 1 | ||||||
| 		else: | 		else: | ||||||
| 			amount_field = (loan_doc.amount_paid).as_("debit") | 			amount_field = (loan_doc.amount_paid).as_("debit") | ||||||
| 			posting_date = (loan_doc.posting_date).as_("posting_date") | 			posting_date = (loan_doc.posting_date).as_("posting_date") | ||||||
| 			account = loan_doc.payment_account | 			account = loan_doc.payment_account | ||||||
|  | 			salary_condition = loan_doc.repay_from_salary == 0 | ||||||
| 
 | 
 | ||||||
| 		query = ( | 		query = ( | ||||||
| 			frappe.qb.from_(loan_doc) | 			frappe.qb.from_(loan_doc) | ||||||
| @ -214,14 +216,12 @@ def get_loan_entries(filters): | |||||||
| 				posting_date, | 				posting_date, | ||||||
| 			) | 			) | ||||||
| 			.where(loan_doc.docstatus == 1) | 			.where(loan_doc.docstatus == 1) | ||||||
|  | 			.where(salary_condition) | ||||||
| 			.where(account == filters.get("account")) | 			.where(account == filters.get("account")) | ||||||
| 			.where(posting_date <= getdate(filters.get("report_date"))) | 			.where(posting_date <= getdate(filters.get("report_date"))) | ||||||
| 			.where(ifnull(loan_doc.clearance_date, "4000-01-01") > getdate(filters.get("report_date"))) | 			.where(ifnull(loan_doc.clearance_date, "4000-01-01") > getdate(filters.get("report_date"))) | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 		if doctype == "Loan Repayment": |  | ||||||
| 			query.where(loan_doc.repay_from_salary == 0) |  | ||||||
| 
 |  | ||||||
| 		entries = query.run(as_dict=1) | 		entries = query.run(as_dict=1) | ||||||
| 		loan_docs.extend(entries) | 		loan_docs.extend(entries) | ||||||
| 
 | 
 | ||||||
| @ -267,15 +267,17 @@ def get_loan_amount(filters): | |||||||
| 			amount_field = Sum(loan_doc.disbursed_amount) | 			amount_field = Sum(loan_doc.disbursed_amount) | ||||||
| 			posting_date = (loan_doc.disbursement_date).as_("posting_date") | 			posting_date = (loan_doc.disbursement_date).as_("posting_date") | ||||||
| 			account = loan_doc.disbursement_account | 			account = loan_doc.disbursement_account | ||||||
|  | 			salary_condition = loan_doc.docstatus == 1 | ||||||
| 		else: | 		else: | ||||||
| 			amount_field = Sum(loan_doc.amount_paid) | 			amount_field = Sum(loan_doc.amount_paid) | ||||||
| 			posting_date = (loan_doc.posting_date).as_("posting_date") | 			posting_date = (loan_doc.posting_date).as_("posting_date") | ||||||
| 			account = loan_doc.payment_account | 			account = loan_doc.payment_account | ||||||
| 
 | 			salary_condition = loan_doc.repay_from_salary == 0 | ||||||
| 		amount = ( | 		amount = ( | ||||||
| 			frappe.qb.from_(loan_doc) | 			frappe.qb.from_(loan_doc) | ||||||
| 			.select(amount_field) | 			.select(amount_field) | ||||||
| 			.where(loan_doc.docstatus == 1) | 			.where(loan_doc.docstatus == 1) | ||||||
|  | 			.where(salary_condition) | ||||||
| 			.where(account == filters.get("account")) | 			.where(account == filters.get("account")) | ||||||
| 			.where(posting_date > getdate(filters.get("report_date"))) | 			.where(posting_date > getdate(filters.get("report_date"))) | ||||||
| 			.where(ifnull(loan_doc.clearance_date, "4000-01-01") <= getdate(filters.get("report_date"))) | 			.where(ifnull(loan_doc.clearance_date, "4000-01-01") <= getdate(filters.get("report_date"))) | ||||||
|  | |||||||
| @ -262,7 +262,10 @@ def get_report_summary(summary_data, currency): | |||||||
| def get_chart_data(columns, data): | def get_chart_data(columns, data): | ||||||
| 	labels = [d.get("label") for d in columns[2:]] | 	labels = [d.get("label") for d in columns[2:]] | ||||||
| 	datasets = [ | 	datasets = [ | ||||||
| 		{"name": account.get("account").replace("'", ""), "values": [account.get("total")]} | 		{ | ||||||
|  | 			"name": account.get("account").replace("'", ""), | ||||||
|  | 			"values": [account.get(d.get("fieldname")) for d in columns[2:]], | ||||||
|  | 		} | ||||||
| 		for account in data | 		for account in data | ||||||
| 		if account.get("parent_account") == None and account.get("currency") | 		if account.get("parent_account") == None and account.get("currency") | ||||||
| 	] | 	] | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ from erpnext.accounts.doctype.pricing_rule.utils import ( | |||||||
| from erpnext.accounts.party import ( | from erpnext.accounts.party import ( | ||||||
| 	get_party_account, | 	get_party_account, | ||||||
| 	get_party_account_currency, | 	get_party_account_currency, | ||||||
|  | 	get_party_gle_currency, | ||||||
| 	validate_party_frozen_disabled, | 	validate_party_frozen_disabled, | ||||||
| ) | ) | ||||||
| from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year | from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year | ||||||
| @ -168,6 +169,7 @@ class AccountsController(TransactionBase): | |||||||
| 
 | 
 | ||||||
| 		self.validate_party() | 		self.validate_party() | ||||||
| 		self.validate_currency() | 		self.validate_currency() | ||||||
|  | 		self.validate_party_account_currency() | ||||||
| 
 | 
 | ||||||
| 		if self.doctype in ["Purchase Invoice", "Sales Invoice"]: | 		if self.doctype in ["Purchase Invoice", "Sales Invoice"]: | ||||||
| 			pos_check_field = "is_pos" if self.doctype == "Sales Invoice" else "is_paid" | 			pos_check_field = "is_pos" if self.doctype == "Sales Invoice" else "is_paid" | ||||||
| @ -1447,6 +1449,27 @@ class AccountsController(TransactionBase): | |||||||
| 				# at quotation / sales order level and we shouldn't stop someone | 				# at quotation / sales order level and we shouldn't stop someone | ||||||
| 				# from creating a sales invoice if sales order is already created | 				# from creating a sales invoice if sales order is already created | ||||||
| 
 | 
 | ||||||
|  | 	def validate_party_account_currency(self): | ||||||
|  | 		if self.doctype not in ("Sales Invoice", "Purchase Invoice"): | ||||||
|  | 			return | ||||||
|  | 
 | ||||||
|  | 		if self.is_opening == "Yes": | ||||||
|  | 			return | ||||||
|  | 
 | ||||||
|  | 		party_type, party = self.get_party() | ||||||
|  | 		party_gle_currency = get_party_gle_currency(party_type, party, self.company) | ||||||
|  | 		party_account = ( | ||||||
|  | 			self.get("debit_to") if self.doctype == "Sales Invoice" else self.get("credit_to") | ||||||
|  | 		) | ||||||
|  | 		party_account_currency = get_account_currency(party_account) | ||||||
|  | 
 | ||||||
|  | 		if not party_gle_currency and (party_account_currency != self.currency): | ||||||
|  | 			frappe.throw( | ||||||
|  | 				_("Party Account {0} currency and document currency should be same").format( | ||||||
|  | 					frappe.bold(party_account) | ||||||
|  | 				) | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
| 	def delink_advance_entries(self, linked_doc_name): | 	def delink_advance_entries(self, linked_doc_name): | ||||||
| 		total_allocated_amount = 0 | 		total_allocated_amount = 0 | ||||||
| 		for adv in self.advances: | 		for adv in self.advances: | ||||||
|  | |||||||
| @ -448,8 +448,6 @@ class LoanRepayment(AccountsController): | |||||||
| 					"remarks": remarks, | 					"remarks": remarks, | ||||||
| 					"cost_center": self.cost_center, | 					"cost_center": self.cost_center, | ||||||
| 					"posting_date": getdate(self.posting_date), | 					"posting_date": getdate(self.posting_date), | ||||||
| 					"party_type": self.applicant_type if self.repay_from_salary else "", |  | ||||||
| 					"party": self.applicant if self.repay_from_salary else "", |  | ||||||
| 				} | 				} | ||||||
| 			) | 			) | ||||||
| 		) | 		) | ||||||
|  | |||||||
| @ -359,7 +359,7 @@ erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr | |||||||
| erpnext.patches.v13_0.update_accounts_in_loan_docs | erpnext.patches.v13_0.update_accounts_in_loan_docs | ||||||
| erpnext.patches.v14_0.update_batch_valuation_flag | erpnext.patches.v14_0.update_batch_valuation_flag | ||||||
| erpnext.patches.v14_0.delete_non_profit_doctypes | erpnext.patches.v14_0.delete_non_profit_doctypes | ||||||
| erpnext.patches.v14_0.update_employee_advance_status | erpnext.patches.v13_0.update_employee_advance_status | ||||||
| erpnext.patches.v13_0.add_cost_center_in_loans | erpnext.patches.v13_0.add_cost_center_in_loans | ||||||
| erpnext.patches.v13_0.set_return_against_in_pos_invoice_references | erpnext.patches.v13_0.set_return_against_in_pos_invoice_references | ||||||
| erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 | erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ from frappe.utils import ( | |||||||
| 	comma_and, | 	comma_and, | ||||||
| 	date_diff, | 	date_diff, | ||||||
| 	flt, | 	flt, | ||||||
|  | 	get_link_to_form, | ||||||
| 	getdate, | 	getdate, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -45,6 +46,7 @@ class PayrollEntry(Document): | |||||||
| 
 | 
 | ||||||
| 	def before_submit(self): | 	def before_submit(self): | ||||||
| 		self.validate_employee_details() | 		self.validate_employee_details() | ||||||
|  | 		self.validate_payroll_payable_account() | ||||||
| 		if self.validate_attendance: | 		if self.validate_attendance: | ||||||
| 			if self.validate_employee_attendance(): | 			if self.validate_employee_attendance(): | ||||||
| 				frappe.throw(_("Cannot Submit, Employees left to mark attendance")) | 				frappe.throw(_("Cannot Submit, Employees left to mark attendance")) | ||||||
| @ -66,6 +68,14 @@ class PayrollEntry(Document): | |||||||
| 		if len(emp_with_sal_slip): | 		if len(emp_with_sal_slip): | ||||||
| 			frappe.throw(_("Salary Slip already exists for {0}").format(comma_and(emp_with_sal_slip))) | 			frappe.throw(_("Salary Slip already exists for {0}").format(comma_and(emp_with_sal_slip))) | ||||||
| 
 | 
 | ||||||
|  | 	def validate_payroll_payable_account(self): | ||||||
|  | 		if frappe.db.get_value("Account", self.payroll_payable_account, "account_type"): | ||||||
|  | 			frappe.throw( | ||||||
|  | 				_( | ||||||
|  | 					"Account type cannot be set for payroll payable account {0}, please remove and try again" | ||||||
|  | 				).format(frappe.bold(get_link_to_form("Account", self.payroll_payable_account))) | ||||||
|  | 			) | ||||||
|  | 
 | ||||||
| 	def on_cancel(self): | 	def on_cancel(self): | ||||||
| 		frappe.delete_doc( | 		frappe.delete_doc( | ||||||
| 			"Salary Slip", | 			"Salary Slip", | ||||||
|  | |||||||
| @ -234,7 +234,7 @@ | |||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|    "fieldname": "actual_start_date", |    "fieldname": "actual_start_date", | ||||||
|    "fieldtype": "Data", |    "fieldtype": "Date", | ||||||
|    "label": "Actual Start Date (via Time Sheet)", |    "label": "Actual Start Date (via Time Sheet)", | ||||||
|    "read_only": 1 |    "read_only": 1 | ||||||
|   }, |   }, | ||||||
| @ -458,7 +458,7 @@ | |||||||
|  "index_web_pages_for_search": 1, |  "index_web_pages_for_search": 1, | ||||||
|  "links": [], |  "links": [], | ||||||
|  "max_attachments": 4, |  "max_attachments": 4, | ||||||
|  "modified": "2022-01-29 13:58:27.712714", |  "modified": "2022-05-25 22:45:06.108499", | ||||||
|  "modified_by": "Administrator", |  "modified_by": "Administrator", | ||||||
|  "module": "Projects", |  "module": "Projects", | ||||||
|  "name": "Project", |  "name": "Project", | ||||||
| @ -504,4 +504,4 @@ | |||||||
|  "timeline_field": "customer", |  "timeline_field": "customer", | ||||||
|  "title_field": "project_name", |  "title_field": "project_name", | ||||||
|  "track_seen": 1 |  "track_seen": 1 | ||||||
| } | } | ||||||
|  | |||||||
| @ -789,11 +789,23 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { | |||||||
| 		if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) { | 		if(this.frm.doc.is_pos && (update_paid_amount===undefined || update_paid_amount)) { | ||||||
| 			$.each(this.frm.doc['payments'] || [], function(index, data) { | 			$.each(this.frm.doc['payments'] || [], function(index, data) { | ||||||
| 				if(data.default && payment_status && total_amount_to_pay > 0) { | 				if(data.default && payment_status && total_amount_to_pay > 0) { | ||||||
| 					let base_amount = flt(total_amount_to_pay, precision("base_amount", data)); | 					let base_amount, amount; | ||||||
|  | 
 | ||||||
|  | 					if (me.frm.doc.party_account_currency == me.frm.doc.currency) { | ||||||
|  | 						// if customer/supplier currency is same as company currency
 | ||||||
|  | 						// total_amount_to_pay is already in customer/supplier currency
 | ||||||
|  | 						// so base_amount has to be calculated using total_amount_to_pay
 | ||||||
|  | 						base_amount = flt(total_amount_to_pay * me.frm.doc.conversion_rate, precision("base_amount", data)); | ||||||
|  | 						amount = flt(total_amount_to_pay, precision("amount", data)); | ||||||
|  | 					} else { | ||||||
|  | 						base_amount = flt(total_amount_to_pay, precision("base_amount", data)); | ||||||
|  | 						amount = flt(total_amount_to_pay / me.frm.doc.conversion_rate, precision("amount", data)); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
| 					frappe.model.set_value(data.doctype, data.name, "base_amount", base_amount); | 					frappe.model.set_value(data.doctype, data.name, "base_amount", base_amount); | ||||||
| 					let amount = flt(total_amount_to_pay / me.frm.doc.conversion_rate, precision("amount", data)); |  | ||||||
| 					frappe.model.set_value(data.doctype, data.name, "amount", amount); | 					frappe.model.set_value(data.doctype, data.name, "amount", amount); | ||||||
| 					payment_status = false; | 					payment_status = false; | ||||||
|  | 
 | ||||||
| 				} else if(me.frm.doc.paid_amount) { | 				} else if(me.frm.doc.paid_amount) { | ||||||
| 					frappe.model.set_value(data.doctype, data.name, "amount", 0.0); | 					frappe.model.set_value(data.doctype, data.name, "amount", 0.0); | ||||||
| 				} | 				} | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ erpnext.setup_auto_gst_taxation = (doctype) => { | |||||||
| 				'shipping_address': frm.doc.shipping_address || '', | 				'shipping_address': frm.doc.shipping_address || '', | ||||||
| 				'shipping_address_name': frm.doc.shipping_address_name || '', | 				'shipping_address_name': frm.doc.shipping_address_name || '', | ||||||
| 				'customer_address': frm.doc.customer_address || '', | 				'customer_address': frm.doc.customer_address || '', | ||||||
|  | 				'company_address': frm.doc.company_address, | ||||||
| 				'supplier_address': frm.doc.supplier_address, | 				'supplier_address': frm.doc.supplier_address, | ||||||
| 				'customer': frm.doc.customer, | 				'customer': frm.doc.customer, | ||||||
| 				'supplier': frm.doc.supplier, | 				'supplier': frm.doc.supplier, | ||||||
|  | |||||||
| @ -448,7 +448,7 @@ class Gstr1Report(object): | |||||||
| 					hsn_code = self.item_hsn_map.get(item_code) | 					hsn_code = self.item_hsn_map.get(item_code) | ||||||
| 					tax_rate = 0 | 					tax_rate = 0 | ||||||
| 					taxable_value = items.get(item_code) | 					taxable_value = items.get(item_code) | ||||||
| 					for rates in hsn_wise_tax_rate.get(hsn_code): | 					for rates in hsn_wise_tax_rate.get(hsn_code, []): | ||||||
| 						if taxable_value > rates.get("minimum_taxable_value"): | 						if taxable_value > rates.get("minimum_taxable_value"): | ||||||
| 							tax_rate = rates.get("tax_rate") | 							tax_rate = rates.get("tax_rate") | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1285,6 +1285,14 @@ class TestPurchaseReceipt(FrappeTestCase): | |||||||
| 		from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import ( | 		from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import ( | ||||||
| 			make_purchase_invoice as create_purchase_invoice, | 			make_purchase_invoice as create_purchase_invoice, | ||||||
| 		) | 		) | ||||||
|  | 		from erpnext.accounts.party import add_party_account | ||||||
|  | 
 | ||||||
|  | 		add_party_account( | ||||||
|  | 			"Supplier", | ||||||
|  | 			"_Test Supplier USD", | ||||||
|  | 			"_Test Company with perpetual inventory", | ||||||
|  | 			"_Test Payable USD - TCP1", | ||||||
|  | 		) | ||||||
| 
 | 
 | ||||||
| 		pi = create_purchase_invoice( | 		pi = create_purchase_invoice( | ||||||
| 			company="_Test Company with perpetual inventory", | 			company="_Test Company with perpetual inventory", | ||||||
| @ -1293,6 +1301,7 @@ class TestPurchaseReceipt(FrappeTestCase): | |||||||
| 			expense_account="_Test Account Cost for Goods Sold - TCP1", | 			expense_account="_Test Account Cost for Goods Sold - TCP1", | ||||||
| 			currency="USD", | 			currency="USD", | ||||||
| 			conversion_rate=70, | 			conversion_rate=70, | ||||||
|  | 			supplier="_Test Supplier USD", | ||||||
| 		) | 		) | ||||||
| 
 | 
 | ||||||
| 		pr = create_purchase_receipt(pi.name) | 		pr = create_purchase_receipt(pi.name) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user