141 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 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 erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 | |
| 	get_dimensions,
 | |
| 	make_dimension_in_accounting_doctypes,
 | |
| )
 | |
| 
 | |
| 
 | |
| def create_accounting_dimension_fields():
 | |
| 	dimensions_and_defaults = get_dimensions()
 | |
| 	if dimensions_and_defaults:
 | |
| 		for dimension in dimensions_and_defaults[0]:
 | |
| 			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 get_columns():
 | |
| 	columns = [
 | |
| 		"name",
 | |
| 		"creation",
 | |
| 		"modified",
 | |
| 		"modified_by",
 | |
| 		"owner",
 | |
| 		"docstatus",
 | |
| 		"posting_date",
 | |
| 		"account_type",
 | |
| 		"account",
 | |
| 		"party_type",
 | |
| 		"party",
 | |
| 		"voucher_type",
 | |
| 		"voucher_no",
 | |
| 		"against_voucher_type",
 | |
| 		"against_voucher_no",
 | |
| 		"amount",
 | |
| 		"amount_in_account_currency",
 | |
| 		"account_currency",
 | |
| 		"company",
 | |
| 		"cost_center",
 | |
| 		"due_date",
 | |
| 		"finance_book",
 | |
| 	]
 | |
| 
 | |
| 	dimensions_and_defaults = get_dimensions()
 | |
| 	if dimensions_and_defaults:
 | |
| 		for dimension in dimensions_and_defaults[0]:
 | |
| 			columns.append(dimension.fieldname)
 | |
| 
 | |
| 	return columns
 | |
| 
 | |
| 
 | |
| def build_insert_query():
 | |
| 	ple = qb.DocType("Payment Ledger Entry")
 | |
| 	columns = get_columns()
 | |
| 	insert_query = qb.into(ple)
 | |
| 
 | |
| 	# build 'insert' columns in query
 | |
| 	insert_query = insert_query.columns(tuple(columns))
 | |
| 
 | |
| 	return insert_query
 | |
| 
 | |
| 
 | |
| def insert_chunk_into_payment_ledger(insert_query, gl_entries):
 | |
| 	if gl_entries:
 | |
| 		columns = get_columns()
 | |
| 
 | |
| 		# build tuple of data with same column order
 | |
| 		for entry in gl_entries:
 | |
| 			data = ()
 | |
| 			for column in columns:
 | |
| 				data += (entry[column],)
 | |
| 			insert_query = insert_query.insert(data)
 | |
| 		insert_query.run()
 | |
| 
 | |
| 
 | |
| def execute():
 | |
| 	if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"):
 | |
| 		# create accounting dimension fields in Payment Ledger
 | |
| 		create_accounting_dimension_fields()
 | |
| 
 | |
| 		gl = qb.DocType("GL Entry")
 | |
| 		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)
 | |
| 		)
 | |
| 
 | |
| 		# primary key(name) for payment ledger records
 | |
| 		generate_name_for_payment_ledger_entries(gl_entries)
 | |
| 
 | |
| 		# 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
 |