Merge branch 'develop' into manual_depr_entries_develop
This commit is contained in:
		
						commit
						2d54bf7199
					
				| @ -56,36 +56,41 @@ frappe.treeview_settings["Account"] = { | ||||
| 			accounts = nodes; | ||||
| 		} | ||||
| 
 | ||||
| 		const get_balances = frappe.call({ | ||||
| 			method: 'erpnext.accounts.utils.get_account_balances', | ||||
| 			args: { | ||||
| 				accounts: accounts, | ||||
| 				company: cur_tree.args.company | ||||
| 			}, | ||||
| 		}); | ||||
| 		frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => { | ||||
| 			if(value) { | ||||
| 
 | ||||
| 		get_balances.then(r => { | ||||
| 			if (!r.message || r.message.length == 0) return; | ||||
| 				const get_balances = frappe.call({ | ||||
| 					method: 'erpnext.accounts.utils.get_account_balances', | ||||
| 					args: { | ||||
| 						accounts: accounts, | ||||
| 						company: cur_tree.args.company | ||||
| 					}, | ||||
| 				}); | ||||
| 
 | ||||
| 			for (let account of r.message) { | ||||
| 				get_balances.then(r => { | ||||
| 					if (!r.message || r.message.length == 0) return; | ||||
| 
 | ||||
| 				const node = cur_tree.nodes && cur_tree.nodes[account.value]; | ||||
| 				if (!node || node.is_root) continue; | ||||
| 					for (let account of r.message) { | ||||
| 
 | ||||
| 				// show Dr if positive since balance is calculated as debit - credit else show Cr
 | ||||
| 				const balance = account.balance_in_account_currency || account.balance; | ||||
| 				const dr_or_cr = balance > 0 ? "Dr": "Cr"; | ||||
| 				const format = (value, currency) => format_currency(Math.abs(value), currency); | ||||
| 						const node = cur_tree.nodes && cur_tree.nodes[account.value]; | ||||
| 						if (!node || node.is_root) continue; | ||||
| 
 | ||||
| 				if (account.balance!==undefined) { | ||||
| 					node.parent && node.parent.find('.balance-area').remove(); | ||||
| 					$('<span class="balance-area pull-right">' | ||||
| 						+ (account.balance_in_account_currency ? | ||||
| 							(format(account.balance_in_account_currency, account.account_currency) + " / ") : "") | ||||
| 						+ format(account.balance, account.company_currency) | ||||
| 						+ " " + dr_or_cr | ||||
| 						+ '</span>').insertBefore(node.$ul); | ||||
| 				} | ||||
| 						// show Dr if positive since balance is calculated as debit - credit else show Cr
 | ||||
| 						const balance = account.balance_in_account_currency || account.balance; | ||||
| 						const dr_or_cr = balance > 0 ? "Dr": "Cr"; | ||||
| 						const format = (value, currency) => format_currency(Math.abs(value), currency); | ||||
| 
 | ||||
| 						if (account.balance!==undefined) { | ||||
| 							node.parent && node.parent.find('.balance-area').remove(); | ||||
| 							$('<span class="balance-area pull-right">' | ||||
| 							  + (account.balance_in_account_currency ? | ||||
| 							     (format(account.balance_in_account_currency, account.account_currency) + " / ") : "") | ||||
| 							  + format(account.balance, account.company_currency) | ||||
| 							  + " " + dr_or_cr | ||||
| 							  + '</span>').insertBefore(node.$ul); | ||||
| 						} | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| @ -56,7 +56,9 @@ | ||||
|   "acc_frozen_upto", | ||||
|   "column_break_25", | ||||
|   "frozen_accounts_modifier", | ||||
|   "report_settings_sb" | ||||
|   "report_settings_sb", | ||||
|   "tab_break_dpet", | ||||
|   "show_balance_in_coa" | ||||
|  ], | ||||
|  "fields": [ | ||||
|   { | ||||
| @ -347,6 +349,17 @@ | ||||
|    "fieldname": "allow_multi_currency_invoices_against_single_party_account", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Allow multi-currency invoices against single party account " | ||||
|   }, | ||||
|   { | ||||
|    "fieldname": "tab_break_dpet", | ||||
|    "fieldtype": "Tab Break", | ||||
|    "label": "Chart Of Accounts" | ||||
|   }, | ||||
|   { | ||||
|    "default": "1", | ||||
|    "fieldname": "show_balance_in_coa", | ||||
|    "fieldtype": "Check", | ||||
|    "label": "Show Balances in Chart Of Accounts" | ||||
|   } | ||||
|  ], | ||||
|  "icon": "icon-cog", | ||||
| @ -354,7 +367,7 @@ | ||||
|  "index_web_pages_for_search": 1, | ||||
|  "issingle": 1, | ||||
|  "links": [], | ||||
|  "modified": "2022-11-27 21:49:52.538655", | ||||
|  "modified": "2023-01-02 12:07:42.434214", | ||||
|  "modified_by": "Administrator", | ||||
|  "module": "Accounts", | ||||
|  "name": "Accounts Settings", | ||||
|  | ||||
| @ -50,6 +50,20 @@ frappe.query_reports["Gross Profit"] = { | ||||
| 			"fieldtype": "Link", | ||||
| 			"options": "Sales Person" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "warehouse", | ||||
| 			"label": __("Warehouse"), | ||||
| 			"fieldtype": "Link", | ||||
| 			"options": "Warehouse", | ||||
| 			"get_query": function () { | ||||
| 				var company = frappe.query_report.get_filter_value('company'); | ||||
| 				return { | ||||
| 					filters: [ | ||||
| 						["Warehouse", "company", "=", company] | ||||
| 					] | ||||
| 				}; | ||||
| 			}, | ||||
| 		}, | ||||
| 	], | ||||
| 	"tree": true, | ||||
| 	"name_field": "parent", | ||||
|  | ||||
| @ -775,6 +775,13 @@ class GrossProfitGenerator(object): | ||||
| 		if self.filters.get("item_code"): | ||||
| 			conditions += " and `tabSales Invoice Item`.item_code = %(item_code)s" | ||||
| 
 | ||||
| 		if self.filters.get("warehouse"): | ||||
| 			warehouse_details = frappe.db.get_value( | ||||
| 				"Warehouse", self.filters.get("warehouse"), ["lft", "rgt"], as_dict=1 | ||||
| 			) | ||||
| 			if warehouse_details: | ||||
| 				conditions += f" and `tabSales Invoice Item`.warehouse in (select name from `tabWarehouse` wh where wh.lft >= {warehouse_details.lft} and wh.rgt <= {warehouse_details.rgt} and warehouse = wh.name)" | ||||
| 
 | ||||
| 		self.si_list = frappe.db.sql( | ||||
| 			""" | ||||
| 			select | ||||
|  | ||||
| @ -305,7 +305,7 @@ def get_returned_qty_map_for_row(return_against, party, row_name, doctype): | ||||
| 			fields += ["sum(abs(`tab{0}`.received_stock_qty)) as received_stock_qty".format(child_doctype)] | ||||
| 
 | ||||
| 	# Used retrun against and supplier and is_retrun because there is an index added for it | ||||
| 	data = frappe.db.get_list( | ||||
| 	data = frappe.get_all( | ||||
| 		doctype, | ||||
| 		fields=fields, | ||||
| 		filters=[ | ||||
|  | ||||
| @ -2,7 +2,8 @@ import frappe | ||||
| from frappe import qb | ||||
| from frappe.query_builder import Case, CustomFunction | ||||
| from frappe.query_builder.custom import ConstantColumn | ||||
| from frappe.query_builder.functions import IfNull | ||||
| from frappe.query_builder.functions import Count, IfNull | ||||
| from frappe.utils import flt | ||||
| 
 | ||||
| from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( | ||||
| 	get_dimensions, | ||||
| @ -17,9 +18,9 @@ def create_accounting_dimension_fields(): | ||||
| 			make_dimension_in_accounting_doctypes(dimension, ["Payment Ledger Entry"]) | ||||
| 
 | ||||
| 
 | ||||
| def generate_name_for_payment_ledger_entries(gl_entries): | ||||
| 	for index, entry in enumerate(gl_entries, 1): | ||||
| 		entry.name = index | ||||
| def generate_name_for_payment_ledger_entries(gl_entries, start): | ||||
| 	for index, entry in enumerate(gl_entries, 0): | ||||
| 		entry.name = start + index | ||||
| 
 | ||||
| 
 | ||||
| def get_columns(): | ||||
| @ -81,6 +82,14 @@ def insert_chunk_into_payment_ledger(insert_query, gl_entries): | ||||
| 
 | ||||
| 
 | ||||
| def execute(): | ||||
| 	""" | ||||
| 	Description: | ||||
| 	Migrate records from `tabGL Entry` to `tabPayment Ledger Entry`. | ||||
| 	Patch is non-resumable. if patch failed or is terminatted abnormally, clear 'tabPayment Ledger Entry' table manually before re-running. Re-running is safe only during V13->V14 update. | ||||
| 
 | ||||
| 	Note: Post successful migration to V14, re-running is NOT-SAFE and SHOULD NOT be attempted. | ||||
| 	""" | ||||
| 
 | ||||
| 	if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"): | ||||
| 		# create accounting dimension fields in Payment Ledger | ||||
| 		create_accounting_dimension_fields() | ||||
| @ -89,52 +98,90 @@ def execute(): | ||||
| 		account = qb.DocType("Account") | ||||
| 		ifelse = CustomFunction("IF", ["condition", "then", "else"]) | ||||
| 
 | ||||
| 		gl_entries = ( | ||||
| 			qb.from_(gl) | ||||
| 			.inner_join(account) | ||||
| 			.on((gl.account == account.name) & (account.account_type.isin(["Receivable", "Payable"]))) | ||||
| 			.select( | ||||
| 				gl.star, | ||||
| 				ConstantColumn(1).as_("docstatus"), | ||||
| 				account.account_type.as_("account_type"), | ||||
| 				IfNull( | ||||
| 					ifelse(gl.against_voucher_type == "", None, gl.against_voucher_type), gl.voucher_type | ||||
| 				).as_("against_voucher_type"), | ||||
| 				IfNull(ifelse(gl.against_voucher == "", None, gl.against_voucher), gl.voucher_no).as_( | ||||
| 					"against_voucher_no" | ||||
| 				), | ||||
| 				# convert debit/credit to amount | ||||
| 				Case() | ||||
| 				.when(account.account_type == "Receivable", gl.debit - gl.credit) | ||||
| 				.else_(gl.credit - gl.debit) | ||||
| 				.as_("amount"), | ||||
| 				# convert debit/credit in account currency to amount in account currency | ||||
| 				Case() | ||||
| 				.when( | ||||
| 					account.account_type == "Receivable", | ||||
| 					gl.debit_in_account_currency - gl.credit_in_account_currency, | ||||
| 				) | ||||
| 				.else_(gl.credit_in_account_currency - gl.debit_in_account_currency) | ||||
| 				.as_("amount_in_account_currency"), | ||||
| 			) | ||||
| 			.where(gl.is_cancelled == 0) | ||||
| 			.orderby(gl.creation) | ||||
| 			.run(as_dict=True) | ||||
| 		# Get Records Count | ||||
| 		accounts = ( | ||||
| 			qb.from_(account) | ||||
| 			.select(account.name) | ||||
| 			.where((account.account_type == "Receivable") | (account.account_type == "Payable")) | ||||
| 			.orderby(account.name) | ||||
| 		) | ||||
| 		un_processed = ( | ||||
| 			qb.from_(gl) | ||||
| 			.select(Count(gl.name)) | ||||
| 			.where((gl.is_cancelled == 0) & (gl.account.isin(accounts))) | ||||
| 			.run() | ||||
| 		)[0][0] | ||||
| 
 | ||||
| 		# primary key(name) for payment ledger records | ||||
| 		generate_name_for_payment_ledger_entries(gl_entries) | ||||
| 		if un_processed: | ||||
| 			print(f"Migrating {un_processed} GL Entries to Payment Ledger") | ||||
| 
 | ||||
| 		# split data into chunks | ||||
| 		chunk_size = 1000 | ||||
| 		try: | ||||
| 			for i in range(0, len(gl_entries), chunk_size): | ||||
| 				insert_query = build_insert_query() | ||||
| 				insert_chunk_into_payment_ledger(insert_query, gl_entries[i : i + chunk_size]) | ||||
| 				frappe.db.commit() | ||||
| 		except Exception as err: | ||||
| 			frappe.db.rollback() | ||||
| 			ple = qb.DocType("Payment Ledger Entry") | ||||
| 			qb.from_(ple).delete().where(ple.docstatus >= 0).run() | ||||
| 			frappe.db.commit() | ||||
| 			raise err | ||||
| 			processed = 0 | ||||
| 			last_update_percent = 0 | ||||
| 			batch_size = 5000 | ||||
| 			last_name = None | ||||
| 
 | ||||
| 			while True: | ||||
| 				if last_name: | ||||
| 					where_clause = gl.name.gt(last_name) & (gl.is_cancelled == 0) | ||||
| 				else: | ||||
| 					where_clause = gl.is_cancelled == 0 | ||||
| 
 | ||||
| 				gl_entries = ( | ||||
| 					qb.from_(gl) | ||||
| 					.inner_join(account) | ||||
| 					.on((gl.account == account.name) & (account.account_type.isin(["Receivable", "Payable"]))) | ||||
| 					.select( | ||||
| 						gl.star, | ||||
| 						ConstantColumn(1).as_("docstatus"), | ||||
| 						account.account_type.as_("account_type"), | ||||
| 						IfNull( | ||||
| 							ifelse(gl.against_voucher_type == "", None, gl.against_voucher_type), gl.voucher_type | ||||
| 						).as_("against_voucher_type"), | ||||
| 						IfNull(ifelse(gl.against_voucher == "", None, gl.against_voucher), gl.voucher_no).as_( | ||||
| 							"against_voucher_no" | ||||
| 						), | ||||
| 						# convert debit/credit to amount | ||||
| 						Case() | ||||
| 						.when(account.account_type == "Receivable", gl.debit - gl.credit) | ||||
| 						.else_(gl.credit - gl.debit) | ||||
| 						.as_("amount"), | ||||
| 						# convert debit/credit in account currency to amount in account currency | ||||
| 						Case() | ||||
| 						.when( | ||||
| 							account.account_type == "Receivable", | ||||
| 							gl.debit_in_account_currency - gl.credit_in_account_currency, | ||||
| 						) | ||||
| 						.else_(gl.credit_in_account_currency - gl.debit_in_account_currency) | ||||
| 						.as_("amount_in_account_currency"), | ||||
| 					) | ||||
| 					.where(where_clause) | ||||
| 					.orderby(gl.name) | ||||
| 					.limit(batch_size) | ||||
| 					.run(as_dict=True) | ||||
| 				) | ||||
| 
 | ||||
| 				if gl_entries: | ||||
| 					last_name = gl_entries[-1].name | ||||
| 
 | ||||
| 					# primary key(name) for payment ledger records | ||||
| 					generate_name_for_payment_ledger_entries(gl_entries, processed) | ||||
| 
 | ||||
| 					try: | ||||
| 						insert_query = build_insert_query() | ||||
| 						insert_chunk_into_payment_ledger(insert_query, gl_entries) | ||||
| 						frappe.db.commit() | ||||
| 
 | ||||
| 						processed += len(gl_entries) | ||||
| 
 | ||||
| 						# Progress message | ||||
| 						percent = flt((processed / un_processed) * 100, 2) | ||||
| 						if percent - last_update_percent > 1: | ||||
| 							print(f"{percent}% ({processed}) records processed") | ||||
| 							last_update_percent = percent | ||||
| 
 | ||||
| 					except Exception as err: | ||||
| 						print("Migration Failed. Clear `tabPayment Ledger Entry` table before re-running") | ||||
| 						raise err | ||||
| 				else: | ||||
| 					break | ||||
| 			print(f"{processed} records have been sucessfully migrated") | ||||
|  | ||||
| @ -1,81 +1,98 @@ | ||||
| import frappe | ||||
| from frappe import qb | ||||
| from frappe.utils import create_batch | ||||
| 
 | ||||
| 
 | ||||
| def remove_duplicate_entries(pl_entries): | ||||
| 	unique_vouchers = set() | ||||
| 	for x in pl_entries: | ||||
| 		unique_vouchers.add( | ||||
| 			(x.company, x.account, x.party_type, x.party, x.voucher_type, x.voucher_no, x.gle_remarks) | ||||
| 		) | ||||
| 
 | ||||
| 	entries = [] | ||||
| 	for x in unique_vouchers: | ||||
| 		entries.append( | ||||
| 			frappe._dict( | ||||
| 				company=x[0], | ||||
| 				account=x[1], | ||||
| 				party_type=x[2], | ||||
| 				party=x[3], | ||||
| 				voucher_type=x[4], | ||||
| 				voucher_no=x[5], | ||||
| 				gle_remarks=x[6], | ||||
| 			) | ||||
| 		) | ||||
| 	return entries | ||||
| from frappe.query_builder import CustomFunction | ||||
| from frappe.query_builder.functions import Count, IfNull | ||||
| from frappe.utils import flt | ||||
| 
 | ||||
| 
 | ||||
| def execute(): | ||||
| 	""" | ||||
| 	Migrate 'remarks' field from 'tabGL Entry' to 'tabPayment Ledger Entry' | ||||
| 	""" | ||||
| 
 | ||||
| 	if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"): | ||||
| 
 | ||||
| 		gle = qb.DocType("GL Entry") | ||||
| 		ple = qb.DocType("Payment Ledger Entry") | ||||
| 
 | ||||
| 		# get ple and their remarks from GL Entry | ||||
| 		pl_entries = ( | ||||
| 			qb.from_(ple) | ||||
| 			.left_join(gle) | ||||
| 			.on( | ||||
| 				(ple.account == gle.account) | ||||
| 				& (ple.party_type == gle.party_type) | ||||
| 				& (ple.party == gle.party) | ||||
| 				& (ple.voucher_type == gle.voucher_type) | ||||
| 				& (ple.voucher_no == gle.voucher_no) | ||||
| 				& (ple.company == gle.company) | ||||
| 			) | ||||
| 			.select( | ||||
| 				ple.company, | ||||
| 				ple.account, | ||||
| 				ple.party_type, | ||||
| 				ple.party, | ||||
| 				ple.voucher_type, | ||||
| 				ple.voucher_no, | ||||
| 				gle.remarks.as_("gle_remarks"), | ||||
| 			) | ||||
| 			.where((ple.delinked == 0) & (gle.is_cancelled == 0)) | ||||
| 			.run(as_dict=True) | ||||
| 		) | ||||
| 		# Get empty PLE records | ||||
| 		un_processed = ( | ||||
| 			qb.from_(ple).select(Count(ple.name)).where((ple.remarks.isnull()) & (ple.delinked == 0)).run() | ||||
| 		)[0][0] | ||||
| 
 | ||||
| 		pl_entries = remove_duplicate_entries(pl_entries) | ||||
| 		if un_processed: | ||||
| 			print(f"Remarks for {un_processed} Payment Ledger records will be updated from GL Entry") | ||||
| 
 | ||||
| 		if pl_entries: | ||||
| 			# split into multiple batches, update and commit for each batch | ||||
| 			ifelse = CustomFunction("IF", ["condition", "then", "else"]) | ||||
| 
 | ||||
| 			processed = 0 | ||||
| 			last_percent_update = 0 | ||||
| 			batch_size = 1000 | ||||
| 			for batch in create_batch(pl_entries, batch_size): | ||||
| 				for entry in batch: | ||||
| 					query = ( | ||||
| 						qb.update(ple) | ||||
| 						.set(ple.remarks, entry.gle_remarks) | ||||
| 						.where( | ||||
| 							(ple.company == entry.company) | ||||
| 							& (ple.account == entry.account) | ||||
| 							& (ple.party_type == entry.party_type) | ||||
| 							& (ple.party == entry.party) | ||||
| 							& (ple.voucher_type == entry.voucher_type) | ||||
| 							& (ple.voucher_no == entry.voucher_no) | ||||
| 						) | ||||
| 					) | ||||
| 					query.run() | ||||
| 			last_name = None | ||||
| 
 | ||||
| 				frappe.db.commit() | ||||
| 			while True: | ||||
| 				if last_name: | ||||
| 					where_clause = (ple.name.gt(last_name)) & (ple.remarks.isnull()) & (ple.delinked == 0) | ||||
| 				else: | ||||
| 					where_clause = (ple.remarks.isnull()) & (ple.delinked == 0) | ||||
| 
 | ||||
| 				# results are deterministic | ||||
| 				names = ( | ||||
| 					qb.from_(ple).select(ple.name).where(where_clause).orderby(ple.name).limit(batch_size).run() | ||||
| 				) | ||||
| 
 | ||||
| 				if names: | ||||
| 					last_name = names[-1][0] | ||||
| 
 | ||||
| 					pl_entries = ( | ||||
| 						qb.from_(ple) | ||||
| 						.left_join(gle) | ||||
| 						.on( | ||||
| 							(ple.account == gle.account) | ||||
| 							& (ple.party_type == gle.party_type) | ||||
| 							& (ple.party == gle.party) | ||||
| 							& (ple.voucher_type == gle.voucher_type) | ||||
| 							& (ple.voucher_no == gle.voucher_no) | ||||
| 							& ( | ||||
| 								ple.against_voucher_type | ||||
| 								== IfNull( | ||||
| 									ifelse(gle.against_voucher_type == "", None, gle.against_voucher_type), gle.voucher_type | ||||
| 								) | ||||
| 							) | ||||
| 							& ( | ||||
| 								ple.against_voucher_no | ||||
| 								== IfNull(ifelse(gle.against_voucher == "", None, gle.against_voucher), gle.voucher_no) | ||||
| 							) | ||||
| 							& (ple.company == gle.company) | ||||
| 							& ( | ||||
| 								((ple.account_type == "Receivable") & (ple.amount == (gle.debit - gle.credit))) | ||||
| 								| (ple.account_type == "Payable") & (ple.amount == (gle.credit - gle.debit)) | ||||
| 							) | ||||
| 							& (gle.remarks.notnull()) | ||||
| 							& (gle.is_cancelled == 0) | ||||
| 						) | ||||
| 						.select(ple.name) | ||||
| 						.distinct() | ||||
| 						.select( | ||||
| 							gle.remarks.as_("gle_remarks"), | ||||
| 						) | ||||
| 						.where(ple.name.isin(names)) | ||||
| 						.run(as_dict=True) | ||||
| 					) | ||||
| 
 | ||||
| 					if pl_entries: | ||||
| 						for entry in pl_entries: | ||||
| 							query = qb.update(ple).set(ple.remarks, entry.gle_remarks).where((ple.name == entry.name)) | ||||
| 							query.run() | ||||
| 
 | ||||
| 						frappe.db.commit() | ||||
| 
 | ||||
| 						processed += len(pl_entries) | ||||
| 						percentage = flt((processed / un_processed) * 100, 2) | ||||
| 						if percentage - last_percent_update > 1: | ||||
| 							print(f"{percentage}% ({processed}) PLE records updated") | ||||
| 							last_percent_update = percentage | ||||
| 
 | ||||
| 				else: | ||||
| 					break | ||||
| 			print("Remarks succesfully migrated") | ||||
|  | ||||
| @ -159,13 +159,18 @@ def update_qty(bin_name, args): | ||||
| 		last_sle_qty = ( | ||||
| 			frappe.qb.from_(sle) | ||||
| 			.select(sle.qty_after_transaction) | ||||
| 			.where((sle.item_code == args.get("item_code")) & (sle.warehouse == args.get("warehouse"))) | ||||
| 			.where( | ||||
| 				(sle.item_code == args.get("item_code")) | ||||
| 				& (sle.warehouse == args.get("warehouse")) | ||||
| 				& (sle.is_cancelled == 0) | ||||
| 			) | ||||
| 			.orderby(CombineDatetime(sle.posting_date, sle.posting_time), order=Order.desc) | ||||
| 			.orderby(sle.creation, order=Order.desc) | ||||
| 			.limit(1) | ||||
| 			.run() | ||||
| 		) | ||||
| 
 | ||||
| 		actual_qty = 0.0 | ||||
| 		if last_sle_qty: | ||||
| 			actual_qty = last_sle_qty[0][0] | ||||
| 
 | ||||
|  | ||||
| @ -888,7 +888,7 @@ def update_billing_percentage(pr_doc, update_modified=True): | ||||
| 	# Update Billing % based on pending accepted qty | ||||
| 	total_amount, total_billed_amount = 0, 0 | ||||
| 	for item in pr_doc.items: | ||||
| 		return_data = frappe.db.get_list( | ||||
| 		return_data = frappe.get_all( | ||||
| 			"Purchase Receipt", | ||||
| 			fields=["sum(abs(`tabPurchase Receipt Item`.qty)) as qty"], | ||||
| 			filters=[ | ||||
|  | ||||
| @ -1179,7 +1179,7 @@ def get_stock_ledger_entries( | ||||
| def get_sle_by_voucher_detail_no(voucher_detail_no, excluded_sle=None): | ||||
| 	return frappe.db.get_value( | ||||
| 		"Stock Ledger Entry", | ||||
| 		{"voucher_detail_no": voucher_detail_no, "name": ["!=", excluded_sle]}, | ||||
| 		{"voucher_detail_no": voucher_detail_no, "name": ["!=", excluded_sle], "is_cancelled": 0}, | ||||
| 		[ | ||||
| 			"item_code", | ||||
| 			"warehouse", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user