From 33cff7735e0765432b7a633ab470cc9e1ef0668b Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 24 Aug 2018 16:02:27 +0530 Subject: [PATCH 1/9] service stop date field added --- .../sales_invoice_item.json | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 70429a46f0..44d5e7729f 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -1566,9 +1566,42 @@ "bold": 0, "collapsible": 0, "columns": 0, - "default": "0", - "fieldname": "enable_deferred_revenue", - "fieldtype": "Check", + "depends_on": "enable_deferred_revenue", + "fieldname": "deferred_revenue_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Deferred Revenue Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "enable_deferred_revenue", + "fieldname": "service_stop_date", + "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -1576,7 +1609,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Enable Deferred Revenue", + "label": "Service Stop Date", "length": 0, "no_copy": 0, "permlevel": 0, @@ -1598,9 +1631,9 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "enable_deferred_revenue", - "fieldname": "deferred_revenue_account", - "fieldtype": "Link", + "default": "0", + "fieldname": "enable_deferred_revenue", + "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -1608,10 +1641,9 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Deferred Revenue Account", + "label": "Enable Deferred Revenue", "length": 0, "no_copy": 0, - "options": "Account", "permlevel": 0, "precision": "", "print_hide": 0, @@ -2648,7 +2680,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-06 05:18:07.578350", + "modified": "2018-08-29 15:22:58.455304", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", @@ -2661,5 +2693,6 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 0, - "track_seen": 0 + "track_seen": 0, + "track_views": 0 } \ No newline at end of file From 243863a2903192b45d59f14f7732d4c4426fe421 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 24 Aug 2018 16:02:48 +0530 Subject: [PATCH 2/9] validation for stop date added --- .../doctype/sales_invoice/sales_invoice.js | 20 +++++++++++++++++++ .../doctype/sales_invoice/sales_invoice.py | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 194c3641d7..32195dd9dd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -740,6 +740,26 @@ frappe.ui.form.on('Sales Invoice Timesheet', { } }) +frappe.ui.form.on('Sales Invoice Item', { + service_stop_date: function(frm, cdt, cdn) { + var child = locals[cdt][cdn]; + + if(child.service_stop_date) { + let start_date = Date.parse(child.service_start_date); + let end_date = Date.parse(child.service_end_date); + let stop_date = Date.parse(child.service_stop_date); + + if(stop_date < start_date) { + frappe.model.set_value(cdt, cdn, "service_stop_date", ""); + frappe.throw(__("Service Stop Date cannot be before Service Start Date")); + } else if (stop_date > end_date) { + frappe.model.set_value(cdt, cdn, "service_stop_date", ""); + frappe.throw(__("Service Stop Date cannot be after Service End Date")); + } + } + } +}) + var calculate_total_billing_amount = function(frm) { var doc = frm.doc; diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index fd77d4b47e..1623227392 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -89,6 +89,9 @@ class SalesInvoice(SellingController): self.update_current_stock() self.validate_delivery_note() + # validate service stop date to lie in between start and end date + self.validate_service_stop_date() + if not self.is_opening: self.is_opening = 'No' @@ -530,6 +533,16 @@ class SalesInvoice(SellingController): if frappe.db.get_value("Sales Order Item", item.so_detail, "delivered_by_supplier"): frappe.throw(_("Could not update stock, invoice contains drop shipping item.")) + def validate_service_stop_date(self): + frappe.errprint("here") + for item in self.items: + print(date_diff(item.service_stop_date, item.service_start_date)) + if item.enable_deferred_revenue: + if date_diff(item.service_stop_date, item.service_start_date) < 0: + frappe.throw(_("Service Stop Date cannot be before Service Start Date")) + elif date_diff(item.service_stop_date, item.service_end_date) > 0: + frappe.throw(_("Service Stop Date cannot be after Service End Date")) + def update_current_stock(self): for d in self.get('items'): if d.item_code and d.warehouse: From 339c2e9f15744102c0ca5a8de5ab6ca9c26183c6 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 24 Aug 2018 17:15:29 +0530 Subject: [PATCH 3/9] book last gl_entry based on service stop date --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 1623227392..1e5166f99e 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1083,11 +1083,14 @@ class SalesInvoice(SellingController): for item in self.get('items'): last_gl_entry = False + if item.service_end_date.month > item.service_stop_date.month: + continue + booking_start_date = getdate(add_months(today(), -1)) booking_start_date = booking_start_date if booking_start_date>item.service_start_date else item.service_start_date booking_end_date = getdate(add_days(today(), -1)) - if booking_end_date>=item.service_end_date: + if booking_end_date>=item.service_end_date or item.service_stop_date<=booking_end_date: last_gl_entry = True booking_end_date = item.service_end_date From d676a67769b52b1698d173ce02befed54abdc32e Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Sat, 25 Aug 2018 20:15:28 +0530 Subject: [PATCH 4/9] validate changing service stop date once its set --- .../doctype/sales_invoice/sales_invoice.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 1e5166f99e..f071a069b2 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -534,15 +534,23 @@ class SalesInvoice(SellingController): frappe.throw(_("Could not update stock, invoice contains drop shipping item.")) def validate_service_stop_date(self): - frappe.errprint("here") + old_doc = frappe.db.get_all("Sales Invoice Item", {"parent": self.name}, ["name", "service_stop_date"]) + old_stop_dates = {} + for d in old_doc: + old_stop_dates[d.name] = d.service_stop_date or "" + for item in self.items: - print(date_diff(item.service_stop_date, item.service_start_date)) if item.enable_deferred_revenue: + print(vars(item)) if date_diff(item.service_stop_date, item.service_start_date) < 0: frappe.throw(_("Service Stop Date cannot be before Service Start Date")) - elif date_diff(item.service_stop_date, item.service_end_date) > 0: + + if date_diff(item.service_stop_date, item.service_end_date) > 0: frappe.throw(_("Service Stop Date cannot be after Service End Date")) + if old_stop_dates[item.name] and item.service_stop_date!=old_stop_dates[item.name]: + frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx))) + def update_current_stock(self): for d in self.get('items'): if d.item_code and d.warehouse: From 4ce8c7f383dc9718b32a080938d70305ead423a9 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 28 Aug 2018 12:16:59 +0530 Subject: [PATCH 5/9] end date should reset if start date is changed --- erpnext/accounts/doctype/sales_invoice/sales_invoice.js | 7 +++++++ erpnext/stock/get_item_details.py | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 32195dd9dd..619c0ed6f9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -757,6 +757,13 @@ frappe.ui.form.on('Sales Invoice Item', { frappe.throw(__("Service Stop Date cannot be after Service End Date")); } } + }, + service_start_date: function(frm, cdt, cdn) { + var child = locals[cdt][cdn]; + + if(child.service_start_date) { + frappe.model.set_value(cdt, cdn, "service_end_date", ""); + } } }) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 420d9d8c3e..caafcdcfa4 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -274,11 +274,12 @@ def get_basic_details(args, item): }) if item.enable_deferred_revenue: - service_end_date = add_months(args.transaction_date, item.no_of_months) + service_start_date = args.service_start_date if args.service_start_date else args.transaction_date + service_end_date = add_months(service_start_date, item.no_of_months) out.update({ "enable_deferred_revenue": item.enable_deferred_revenue, "deferred_revenue_account": get_default_deferred_revenue_account(args, item), - "service_start_date": args.transaction_date, + "service_start_date": service_start_date, "service_end_date": service_end_date }) From 7b3fd859438277cdd73f763186fbb2ac4d932da7 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 28 Aug 2018 12:42:32 +0530 Subject: [PATCH 6/9] end date / stop date calc fix --- .../accounts/doctype/sales_invoice/sales_invoice.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f071a069b2..13e087a54a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -541,7 +541,6 @@ class SalesInvoice(SellingController): for item in self.items: if item.enable_deferred_revenue: - print(vars(item)) if date_diff(item.service_stop_date, item.service_start_date) < 0: frappe.throw(_("Service Stop Date cannot be before Service Start Date")) @@ -1091,16 +1090,18 @@ class SalesInvoice(SellingController): for item in self.get('items'): last_gl_entry = False - if item.service_end_date.month > item.service_stop_date.month: - continue - booking_start_date = getdate(add_months(today(), -1)) booking_start_date = booking_start_date if booking_start_date>item.service_start_date else item.service_start_date booking_end_date = getdate(add_days(today(), -1)) - if booking_end_date>=item.service_end_date or item.service_stop_date<=booking_end_date: + if booking_end_date.month > item.service_stop_date.month: + continue + elif booking_end_date>=item.service_end_date: last_gl_entry = True booking_end_date = item.service_end_date + elif item.service_stop_date<=booking_end_date: + last_gl_entry = True + booking_end_date = item.service_stop_date total_days = date_diff(item.service_end_date, item.service_start_date) total_booking_days = date_diff(booking_end_date, booking_start_date) + 1 From d0e37327e62796b8e8f7ecd9fbe54de2bbf8e7af Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 28 Aug 2018 14:24:21 +0530 Subject: [PATCH 7/9] start date logic fix --- .../accounts/doctype/sales_invoice/sales_invoice.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 13e087a54a..443696c409 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1093,6 +1093,18 @@ class SalesInvoice(SellingController): booking_start_date = getdate(add_months(today(), -1)) booking_start_date = booking_start_date if booking_start_date>item.service_start_date else item.service_start_date + if item.service_start_date < booking_start_date: + prev_gl_entry = frappe.db.sql(''' + select name, posting_date from `tabGL Entry` where company=%s and account=%s and + voucher_type=%s and voucher_no=%s and voucher_detail_no=%s + order by posting_date desc limit 1 + ''', (self.company, item.deferred_revenue_account, "Sales Invoice", self.name, item.name), as_dict=True)[0] + + if not prev_gl_entry: + booking_start_date = item.service_start_date + else: + booking_start_date = getdate(add_days(prev_gl_entry.posting_date, 1)) + booking_end_date = getdate(add_days(today(), -1)) if booking_end_date.month > item.service_stop_date.month: continue From 91eae543831c7007d83584f1367ec1f1e96f64ca Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 28 Aug 2018 15:41:03 +0530 Subject: [PATCH 8/9] manually provide start and end date --- .../accounts/doctype/sales_invoice/sales_invoice.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 443696c409..5ab9de3e0a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1081,7 +1081,7 @@ class SalesInvoice(SellingController): if points_to_redeem < 1: # since points_to_redeem is integer break - def book_income_for_deferred_revenue(self): + def book_income_for_deferred_revenue(self, start_date=None, end_date=None): # book the income on the last day, but it will be trigger on the 1st of month at 12:00 AM # start_date: 1st of the last month or the start date # end_date: end_date or today-1 @@ -1115,6 +1115,11 @@ class SalesInvoice(SellingController): last_gl_entry = True booking_end_date = item.service_stop_date + if start_date and end_date: + # if start and end date are already provided + booking_start_date = start_date + booking_end_date = end_date + total_days = date_diff(item.service_end_date, item.service_start_date) total_booking_days = date_diff(booking_end_date, booking_start_date) + 1 @@ -1166,17 +1171,17 @@ class SalesInvoice(SellingController): make_gl_entries(gl_entries, cancel=(self.docstatus == 2), merge_entries=True) -def booked_deferred_revenue(): +def booked_deferred_revenue(start_date=None, end_date=None): # check for the sales invoice for which GL entries has to be done invoices = frappe.db.sql_list(''' select parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s and enable_deferred_revenue = 1 and docstatus = 1 - ''', (today(), add_months(today(), -1))) + ''', (start_date or today(), end_date or add_months(today(), -1))) # ToDo also find the list on the basic of the GL entry, and make another list for invoice in invoices: doc = frappe.get_doc("Sales Invoice", invoice) - doc.book_income_for_deferred_revenue() + doc.book_income_for_deferred_revenue(start_date, end_date) def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference): From 80f5cb05cc9cf5721d5db45c0421472fc713e1e8 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 29 Aug 2018 11:39:08 +0530 Subject: [PATCH 9/9] fixes in setting end_date and manual provision of start&end date --- .../doctype/sales_invoice/sales_invoice.js | 8 +++++- .../doctype/sales_invoice/sales_invoice.py | 17 +++++-------- erpnext/stock/get_item_details.py | 25 +++++++++++++------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 619c0ed6f9..d3728e4ca9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -762,7 +762,13 @@ frappe.ui.form.on('Sales Invoice Item', { var child = locals[cdt][cdn]; if(child.service_start_date) { - frappe.model.set_value(cdt, cdn, "service_end_date", ""); + frappe.call({ + "method": "erpnext.stock.get_item_details.calculate_service_end_date", + args: {"args": child}, + callback: function(r) { + frappe.model.set_value(cdt, cdn, "service_end_date", r.message.service_end_date); + } + }) } } }) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 5ab9de3e0a..664231a860 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -547,7 +547,7 @@ class SalesInvoice(SellingController): if date_diff(item.service_stop_date, item.service_end_date) > 0: frappe.throw(_("Service Stop Date cannot be after Service End Date")) - if old_stop_dates[item.name] and item.service_stop_date!=old_stop_dates[item.name]: + if old_stop_dates and old_stop_dates[item.name] and item.service_stop_date!=old_stop_dates[item.name]: frappe.throw(_("Cannot change Service Stop Date for item in row {0}".format(item.idx))) def update_current_stock(self): @@ -1090,7 +1090,7 @@ class SalesInvoice(SellingController): for item in self.get('items'): last_gl_entry = False - booking_start_date = getdate(add_months(today(), -1)) + booking_start_date = getdate(add_months(today(), -1)) if not start_date else start_date booking_start_date = booking_start_date if booking_start_date>item.service_start_date else item.service_start_date if item.service_start_date < booking_start_date: @@ -1105,21 +1105,16 @@ class SalesInvoice(SellingController): else: booking_start_date = getdate(add_days(prev_gl_entry.posting_date, 1)) - booking_end_date = getdate(add_days(today(), -1)) - if booking_end_date.month > item.service_stop_date.month: + booking_end_date = getdate(add_days(today(), -1)) if not end_date else end_date + if item.service_stop_date and booking_end_date.month > item.service_stop_date.month: continue elif booking_end_date>=item.service_end_date: last_gl_entry = True booking_end_date = item.service_end_date - elif item.service_stop_date<=booking_end_date: + elif item.service_stop_date and item.service_stop_date<=booking_end_date: last_gl_entry = True booking_end_date = item.service_stop_date - if start_date and end_date: - # if start and end date are already provided - booking_start_date = start_date - booking_end_date = end_date - total_days = date_diff(item.service_end_date, item.service_start_date) total_booking_days = date_diff(booking_end_date, booking_start_date) + 1 @@ -1176,7 +1171,7 @@ def booked_deferred_revenue(start_date=None, end_date=None): invoices = frappe.db.sql_list(''' select parent from `tabSales Invoice Item` where service_start_date<=%s and service_end_date>=%s and enable_deferred_revenue = 1 and docstatus = 1 - ''', (start_date or today(), end_date or add_months(today(), -1))) + ''', (end_date or today(), start_date or add_months(today(), -1))) # ToDo also find the list on the basic of the GL entry, and make another list for invoice in invoices: diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index caafcdcfa4..b6a08afc09 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -274,14 +274,7 @@ def get_basic_details(args, item): }) if item.enable_deferred_revenue: - service_start_date = args.service_start_date if args.service_start_date else args.transaction_date - service_end_date = add_months(service_start_date, item.no_of_months) - out.update({ - "enable_deferred_revenue": item.enable_deferred_revenue, - "deferred_revenue_account": get_default_deferred_revenue_account(args, item), - "service_start_date": service_start_date, - "service_end_date": service_end_date - }) + out.update(calculate_service_end_date(args, item)) # calculate conversion factor if item.stock_uom == args.uom: @@ -311,6 +304,22 @@ def get_basic_details(args, item): return out +@frappe.whitelist() +def calculate_service_end_date(args, item=None): + args = process_args(args) + if not item: + item = frappe.get_cached_doc("Item", args.item_code) + + service_start_date = args.service_start_date if args.service_start_date else args.transaction_date + service_end_date = add_months(service_start_date, item.no_of_months) + deferred_detail = { + "enable_deferred_revenue": item.enable_deferred_revenue, + "deferred_revenue_account": get_default_deferred_revenue_account(args, item), + "service_start_date": service_start_date, + "service_end_date": service_end_date + } + + return deferred_detail def get_default_income_account(args, item, item_group): return (item.get("income_account")