diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 2b6452d0c6e..9a7ec7c8321 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -463,7 +463,6 @@ execute:frappe.delete_doc_if_exists("DocType", "Program Fee") erpnext.patches.v9_0.set_pos_profile_name erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings execute:frappe.delete_doc_if_exists("DocType", "Program Fee") -erpnext.patches.v8_10.update_gl_due_date_for_pi_and_si erpnext.patches.v8_10.change_default_customer_credit_days erpnext.patches.v9_0.update_employee_loan_details erpnext.patches.v9_2.delete_healthcare_domain_default_items @@ -484,3 +483,6 @@ erpnext.patches.v10_0.set_primary_contact_for_customer erpnext.patches.v10_0.copy_projects_renamed_fields erpnext.patches.v10_0.enabled_regional_print_format_based_on_country erpnext.patches.v10_0.update_asset_calculate_depreciation +erpnext.patches.v10_0.enabled_regional_print_format_based_on_country +erpnext.patches.v10_0.update_asset_calculate_depreciation +erpnext.patches.v10_0.update_due_date_in_gle_and_payment_entries diff --git a/erpnext/patches/v10_0/update_due_date_in_gle_and_payment_entries.py b/erpnext/patches/v10_0/update_due_date_in_gle_and_payment_entries.py new file mode 100644 index 00000000000..268b84314d2 --- /dev/null +++ b/erpnext/patches/v10_0/update_due_date_in_gle_and_payment_entries.py @@ -0,0 +1,100 @@ +from __future__ import unicode_literals +import frappe +from frappe.utils import update_progress_bar + +def execute(): + frappe.reload_doc("accounts", "doctype", "gl_entry") + frappe.reload_doc("accounts", "doctype", "payment_entry_reference") + frappe.reload_doc("accounts", "doctype", "journal_entry_account") + + print "Updating Due Date in GL Entry, Journal Entry and Payment Entry" + for doctype in ("Sales Invoice", "Purchase Invoice"): + invoice_due_dates = frappe.db.sql("""select name, due_date from `tab{0}` + where docstatus=1 order by name""".format(doctype)) + + # update gle + count = 0 + total_count = len(invoice_due_dates) + batch_size = 1000 + + while(count < total_count): + update_progress_bar("Based on {0}".format(doctype), count, total_count) + sub_set = invoice_due_dates[count:count+batch_size] + invoices = [d[0] for d in sub_set] + + update_gl_entries(doctype, invoices, sub_set) + update_payment_entries(doctype, invoices, sub_set) + + count += batch_size + +def update_gl_entries(doctype, invoices, invoice_due_dates): + when_then = get_when_then_for_gle(doctype, invoice_due_dates) + + frappe.db.sql(""" + UPDATE `tabGL Entry` + SET due_date = CASE + %s + ELSE `due_date` END + WHERE + ( + (voucher_type = %s and voucher_no in (%s)) + or (voucher_type in ('Journal Entry', 'Payment Entry') + and against_voucher in (%s)) + ) + and ifnull(party, '') != '' + and ifnull(due_date, '') = '' + """ % (when_then, '%s', ', '.join(['%s']*len(invoices)), ', '.join(['%s']*len(invoices))), + tuple([doctype] + invoices + invoices)) + +def get_when_then_for_gle(doctype, data): + cond = "" + for d in data: + cond += """ + WHEN ( + (voucher_type = '{voucher_type}' and voucher_no = '{voucher_no}') + or (voucher_type in ('Journal Entry', 'Payment Entry') + and against_voucher = '{voucher_no}') + ) THEN '{date}' + """.format(voucher_type=doctype, voucher_no=frappe.db.escape(d[0]), date=d[1]) + + return cond + +def update_payment_entries(ref_doctype, invoices, invoice_due_dates): + for d in ( + ("Payment Entry Reference", "reference_doctype", "due_date"), + ("Journal Entry Account", "reference_type", "reference_due_date")): + + when_then = get_when_then_for_payment_entries(ref_doctype, d[1], invoice_due_dates) + + frappe.db.sql(""" + UPDATE `tab{doctype}` + SET {due_date_field} = CASE + {when_then} + ELSE `{due_date_field}` END + WHERE + {ref_doctype_fieldname} = '{ref_doctype}' + and reference_name in ({reference_names}) + and ifnull({due_date_field}, '') = '' + """.format( + doctype = d[0], + due_date_field = d[2], + when_then = when_then, + ref_doctype_fieldname = d[1], + ref_doctype = ref_doctype, + reference_names = ', '.join(['%s']*len(invoices)) + ), tuple(invoices)) + +def get_when_then_for_payment_entries(ref_doctype, ref_doctype_fieldname, data): + cond = "" + for d in data: + cond += """ + WHEN {ref_doctype_fieldname} = '{ref_doctype}' + and reference_name = '{voucher_no}' + THEN '{date}' + """.format( + ref_doctype_fieldname=ref_doctype_fieldname, + ref_doctype=ref_doctype, + voucher_no=frappe.db.escape(d[0]), + date=d[1]) + + return cond \ No newline at end of file diff --git a/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py b/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py deleted file mode 100644 index 8596e66cac8..00000000000 --- a/erpnext/patches/v8_10/update_gl_due_date_for_pi_and_si.py +++ /dev/null @@ -1,138 +0,0 @@ -from __future__ import unicode_literals -import frappe - -# This will update existing GL Entries by saving its linked Purchase/Sales Invoice's -# Journal Entry's due date as the due date for the GL Entry - - -def execute(): - frappe.reload_doc("accounts", "doctype", "gl_entry") - - kwargs = get_query_kwargs() - - for kwarg in kwargs: - for batch in get_result_in_batches(**kwarg): - voucher_num_col = kwarg.get('voucher_num_col', 'voucher_no') - voucher_type = kwarg.get('use_voucher_type') or kwarg.get('voucher_type') - conditions, names = build_conditions(batch, voucher_type, voucher_num_col) - if conditions and names: - start = 'UPDATE `tabGL Entry` SET `due_date` = CASE ' - cond = ' '.join(conditions) - else_cond = ' ELSE `due_date` END WHERE ' - - frappe.db.sql( - start + cond + else_cond + voucher_num_col + ' IN %s', - values=(names,) - ) - - -def get_result_in_batches(**kwargs): - """A simple generator to yield slices of GL Entry records""" - while True: - batch = get_gle_batch(**kwargs) - if batch: - yield batch - else: - return - - -def get_gle_batch(**kwargs): - """Returns a slice of records in GL Entry""" - doctype = kwargs.get('doctype') - fields = kwargs.get('fields') - limit_start = kwargs.get('limit_start') - limit_page_length = kwargs.get('limit_page_length') - filters = kwargs.get('filters') - or_filters = kwargs.get('or_filters') - - results = frappe.get_list( - doctype, fields=fields, limit_start=limit_start, limit_page_length=limit_page_length, - filters=filters, or_filters=or_filters - ) - - return results - - -def build_conditions(query_results, voucher_type, voucher_num_col): - """ - builds the string to be used is sql CASE statement. Returns the a tuple of - the string for the CASE statement and a tuple of applicable voucher names - """ - conditions = [] - invoice_names = [] - - for result in query_results: - voucher_no = result.get(voucher_num_col) - if voucher_no: - invoice_names.append("%s" % (voucher_no,)) - - # get invoice details - invoice_details = frappe.get_list( - voucher_type, fields=['name', 'due_date'], filters={'name': ('in', invoice_names)} - ) - - if invoice_details: - for d in invoice_details: - conditions.append('WHEN `{voucher_no}`="{number}" THEN "{date}"'.format( - number=d.name, date=d.due_date, voucher_no=voucher_num_col)) - - return conditions, invoice_names - - -def get_query_kwargs(): - pi_kwargs = dict( - voucher_type='Purchase Invoice', doctype='GL Entry', fields=['voucher_no'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Purchase Invoice', 'credit': ('!=', '0') - } - ) - - si_kwargs = dict( - voucher_type='Sales Invoice', doctype='GL Entry', fields=['voucher_no'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Sales Invoice', 'debit': ('!=', '0') - } - ) - - journal_kwargs_si = dict( - voucher_type='Journal Entry', doctype='GL Entry', fields=['against_voucher'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Journal Entry', 'against_voucher_type': 'Sales Invoice' - }, - voucher_num_col='against_voucher', use_voucher_type='Sales Invoice', - ) - - journal_kwargs_pi = dict( - voucher_type='Journal Entry', doctype='GL Entry', fields=['against_voucher'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Journal Entry', 'against_voucher_type': 'Purchase Invoice' - }, - voucher_num_col='against_voucher', use_voucher_type='Purchase Invoice', - ) - - payment_entry_kwargs_pi = dict( - voucher_type='Payment Entry', doctype='GL Entry', fields=['against_voucher'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Payment Entry', 'against_voucher_type': 'Purchase Invoice' - }, - voucher_num_col='against_voucher', use_voucher_type='Purchase Invoice', - ) - - payment_entry_kwargs_si = dict( - voucher_type='Payment Entry', doctype='GL Entry', fields=['against_voucher'], - limit_start=0, limit_page_length=5, filters={ - "ifnull(due_date, '')": ('=', ''), "ifnull(party, '')": ('!=', ''), - 'voucher_type': 'Payment Entry', 'against_voucher_type': 'Sales Invoice' - }, - voucher_num_col='against_voucher', use_voucher_type='Sales Invoice', - ) - - return [ - pi_kwargs, si_kwargs, journal_kwargs_pi, journal_kwargs_si, - payment_entry_kwargs_pi, payment_entry_kwargs_si - ]