From cc8644f86e4805e717d4bf80ff77a6be1337b203 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 7 Sep 2016 12:28:44 +0530 Subject: [PATCH 1/9] [Timesheet] Field rearrange --- .../doctype/sales_invoice/sales_invoice.json | 83 ++++++++----- .../projects/doctype/timesheet/timesheet.json | 12 +- .../timesheet_detail/timesheet_detail.json | 109 +++++++++++++----- 3 files changed, 142 insertions(+), 62 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 562eaaac53..ffe5237b7d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1079,6 +1079,59 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "project_detail", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "project", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Project", + "length": 0, + "no_copy": 0, + "oldfieldname": "project_name", + "oldfieldtype": "Link", + "options": "Project", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -2873,34 +2926,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 0, - "label": "Project", - "length": 0, - "no_copy": 0, - "oldfieldname": "project_name", - "oldfieldtype": "Link", - "options": "Project", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -3867,7 +3892,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-08-31 15:47:32.064861", + "modified": "2016-09-07 03:04:15.927629", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index cba48593e2..781fa03e1f 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -470,8 +470,8 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "working_hours", "columns": 0, + "fieldname": "working_hours", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, @@ -522,6 +522,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 1, + "columns": 0, "fieldname": "billing_details", "fieldtype": "Section Break", "hidden": 0, @@ -544,9 +545,10 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "total_billing_hours", "fieldtype": "Float", "hidden": 0, @@ -559,9 +561,9 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -737,7 +739,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-09-01 11:33:38.110421", + "modified": "2016-09-07 02:54:20.930768", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json index 9bd4b8df7e..560ce9f7a8 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json @@ -10,33 +10,6 @@ "document_type": "Document", "editable_grid": 1, "fields": [ - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 1, - "depends_on": "", - "fieldname": "billable", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Bill", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -165,6 +138,58 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 1, + "depends_on": "", + "fieldname": "billable", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Bill", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -195,6 +220,7 @@ "allow_on_submit": 1, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "billing_hours", "fieldtype": "Float", "hidden": 0, @@ -351,6 +377,33 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "fieldname": "billed_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Billed Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -577,7 +630,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-08-26 03:00:11.431794", + "modified": "2016-09-07 02:55:22.545715", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet Detail", From a6927e05ba840e6f9f51eed601e978b9bca15921 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 7 Sep 2016 14:39:17 +0530 Subject: [PATCH 2/9] set project wise timesheet data --- .../doctype/sales_invoice/sales_invoice.js | 17 ++++++++--- .../doctype/sales_invoice/sales_invoice.py | 21 +++++++++++++ .../projects/doctype/timesheet/timesheet.json | 28 ++++++++++++++++- .../projects/doctype/timesheet/timesheet.py | 30 +++++++++++++++++++ 4 files changed, 91 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 4886deaa71..47ebc3da78 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -462,12 +462,21 @@ cur_frm.set_query("asset", "items", function(doc, cdt, cdn) { frappe.ui.form.on('Sales Invoice', { setup: function(frm){ frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function(doc, cdt, cdn){ - return { - filters: [ - ["Timesheet", "status", "in", ["Submitted", "Payslip"]] - ] + return{ + query: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet", + filters: {'project': doc.project} } } + }, + + project: function(frm){ + frm.call({ + method: "add_timesheet_data", + doc: frm.doc, + callback: function(r, rt) { + refresh_field(['timesheets']) + } + }) } }) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ec72be1bad..34296eabe8 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -14,6 +14,7 @@ from erpnext.accounts.doctype.sales_invoice.pos import update_multi_mode_option from erpnext.controllers.selling_controller import SellingController from erpnext.accounts.utils import get_account_currency from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so +from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data from erpnext.accounts.doctype.asset.depreciation \ import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal @@ -221,11 +222,19 @@ class SalesInvoice(SellingController): for d in self.timesheets: if d.time_sheet: timesheet = frappe.get_doc("Timesheet", d.time_sheet) + self.update_time_sheet_detail(timesheet, d) timesheet.sales_invoice = sales_invoice timesheet.flags.ignore_validate_update_after_submit = True timesheet.set_status() timesheet.save() + def update_time_sheet_detail(self, timesheet, args): + for data in timesheet.time_logs: + if (self.project and self.project == data.project) or \ + (not self.project and (data.billing_amount - data.billed_amount) > 0): + data.billed_amount = args.billing_amount + if self.project: return + def on_update(self): self.set_paid_amount() @@ -464,6 +473,18 @@ class SalesInvoice(SellingController): self.total_billing_amount = total_billing_amount + def add_timesheet_data(self): + self.set('timesheets', []) + if self.project: + for data in get_projectwise_timesheet_data(self.project): + self.append('timesheets', { + 'time_sheet': data.parent, + 'billing_hours': data.billing_hours, + 'billing_amount': data.billing_amt + }) + + self.calculate_billing_amount_from_timesheet() + def get_warehouse(self): user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile` where ifnull(user,'') = %s and company = %s""", (frappe.session['user'], self.company)) diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index 781fa03e1f..1c174c81f8 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -570,6 +570,32 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_billed_amount", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Total Billed Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -739,7 +765,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-09-07 02:54:20.930768", + "modified": "2016-09-07 06:48:27.316087", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index 63cb8981d0..68a8f4d555 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -31,6 +31,7 @@ class Timesheet(Document): self.total_billing_hours = 0.0 self.total_billing_amount = 0.0 self.total_costing_amount = 0.0 + self.total_billed_amount = 0.0 for d in self.get("time_logs"): self.update_billing_hours(d) @@ -40,6 +41,7 @@ class Timesheet(Document): if d.billable: self.total_billing_amount += flt(d.billing_amount) self.total_costing_amount += flt(d.costing_amount) + self.total_billed_amount += flt(d.billed_amount) def update_billing_hours(self, args): if cint(args.billing_hours) == 0: @@ -245,6 +247,34 @@ class Timesheet(Document): data.billing_amount = data.billing_rate * hours data.costing_amount = data.costing_rate * hours +@frappe.whitelist() +def get_projectwise_timesheet_data(project, parent=None): + cond = '' + if parent: + cond = "and parent = %(parent)s" + + return frappe.db.sql("""select parent, billing_hours, (billing_amount - billed_amount) as billing_amt + from `tabTimesheet Detail` where docstatus=1 and project = %(project)s {0} + having billing_amt > 0""".format(cond), {'project': project, 'parent': parent}, as_dict=1) + +@frappe.whitelist() +def get_timesheet(doctype, txt, searchfield, start, page_len, filters): + if not filters: filters = {} + + condition = "" + if filters.get("project"): + condition = "and tsd.project = %(project)s" + + return frappe.db.sql("""select distinct tsd.parent from `tabTimesheet Detail` tsd, + `tabTimesheet` ts where ts.status in ('Submitted', 'Payslip') and + (tsd.billing_amount - tsd.billed_amount) > 0 and + tsd.docstatus = 1 and tsd.parent LIKE %(txt)s {condition} + order by tsd.parent limit %(start)s, %(page_len)s""" + .format(condition=condition), { + "txt": "%%%s%%" % frappe.db.escape(txt), + "start": start, "page_len": page_len, 'project': filters.get("project") + }) + @frappe.whitelist() def make_sales_invoice(source_name, target=None): target = frappe.new_doc("Sales Invoice") From 3815ebff8ae2dc29c956783174c7b05bcf147037 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 8 Sep 2016 18:17:43 +0530 Subject: [PATCH 3/9] Added %billed in timesheet --- .../doctype/sales_invoice/sales_invoice.js | 22 +++-- .../doctype/sales_invoice/sales_invoice.json | 83 +++++++------------ .../doctype/sales_invoice/sales_invoice.py | 17 ++-- .../sales_invoice_timesheet.json | 31 ++++++- .../projects/doctype/timesheet/timesheet.js | 4 +- .../projects/doctype/timesheet/timesheet.json | 70 ++++++++++++++-- .../projects/doctype/timesheet/timesheet.py | 61 +++++++++----- .../timesheet_detail/timesheet_detail.json | 82 +++++++++++------- 8 files changed, 240 insertions(+), 130 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 47ebc3da78..47f1a5c1c3 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -481,16 +481,22 @@ frappe.ui.form.on('Sales Invoice', { }) frappe.ui.form.on('Sales Invoice Timesheet', { - time_sheet: function(frm){ - frm.call({ - method: "calculate_billing_amount_from_timesheet", - doc: frm.doc, + time_sheet: function(frm, cdt, cdn){ + var d = locals[cdt][cdn]; + frappe.call({ + method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data", + args: { + 'name': d.time_sheet, + 'project': frm.doc.project || null + }, callback: function(r, rt) { - refresh_field('total_billing_amount') + if(r.message){ + data = r.message; + frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours); + frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount); + frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail); + } } }) } }) - -cur_frm.add_fetch("time_sheet", "total_billing_hours", "billing_hours"); -cur_frm.add_fetch("time_sheet", "total_billing_amount", "billing_amount"); \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index ffe5237b7d..99b479348a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -337,6 +337,34 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "project", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Project", + "length": 0, + "no_copy": 0, + "oldfieldname": "project_name", + "oldfieldtype": "Link", + "options": "Project", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -1079,59 +1107,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "project_detail", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_list_view": 0, - "label": "Project", - "length": 0, - "no_copy": 0, - "oldfieldname": "project_name", - "oldfieldtype": "Link", - "options": "Project", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -3892,7 +3867,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-09-07 03:04:15.927629", + "modified": "2016-09-08 09:05:02.895682", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 34296eabe8..f75a9af8ab 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -222,17 +222,19 @@ class SalesInvoice(SellingController): for d in self.timesheets: if d.time_sheet: timesheet = frappe.get_doc("Timesheet", d.time_sheet) - self.update_time_sheet_detail(timesheet, d) - timesheet.sales_invoice = sales_invoice + self.update_time_sheet_detail(timesheet, d, sales_invoice) + timesheet.calculate_total_amounts() + timesheet.calculate_percentage_billed() timesheet.flags.ignore_validate_update_after_submit = True timesheet.set_status() timesheet.save() - def update_time_sheet_detail(self, timesheet, args): + def update_time_sheet_detail(self, timesheet, args, sales_invoice): for data in timesheet.time_logs: - if (self.project and self.project == data.project) or \ - (not self.project and (data.billing_amount - data.billed_amount) > 0): - data.billed_amount = args.billing_amount + if (self.project and args.timesheet_detail == data.name) or \ + (not self.project and not data.sales_invoice) or \ + (not sales_invoice and data.sales_invoice == self.name): + data.sales_invoice = sales_invoice if self.project: return def on_update(self): @@ -480,7 +482,8 @@ class SalesInvoice(SellingController): self.append('timesheets', { 'time_sheet': data.parent, 'billing_hours': data.billing_hours, - 'billing_amount': data.billing_amt + 'billing_amount': data.billing_amt, + 'timesheet_detail': data.name }) self.calculate_billing_amount_from_timesheet() diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json index 25dd3cb845..e34accad9c 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json @@ -14,6 +14,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "time_sheet", "fieldtype": "Link", "hidden": 0, @@ -40,6 +41,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "billing_hours", "fieldtype": "Float", "hidden": 0, @@ -65,6 +67,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "billing_amount", "fieldtype": "Currency", "hidden": 0, @@ -85,6 +88,32 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "timesheet_detail", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Timesheet Detail", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -97,7 +126,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-08-22 21:32:55.504103", + "modified": "2016-09-08 05:36:00.922319", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 42fe005dfc..a47b4ac44a 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -31,7 +31,7 @@ frappe.ui.form.on("Timesheet", { refresh: function(frm) { if(frm.doc.docstatus==1) { - if(!frm.doc.sales_invoice && frm.doc.total_billing_amount > 0){ + if(frm.doc.per_billed < 100){ frm.add_custom_button(__("Make Sales Invoice"), function() { frm.trigger("make_invoice") }, "icon-file-alt"); } @@ -42,7 +42,7 @@ frappe.ui.form.on("Timesheet", { } } - if(frm.doc.sales_invoice) { + if(frm.doc.per_billed > 0) { cur_frm.fields_dict["time_logs"].grid.toggle_enable("billing_hours", false); } }, diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index 1c174c81f8..caa3e7e1b0 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -571,23 +571,49 @@ "unique": 0 }, { - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "total_billed_amount", + "fieldname": "total_billed_hours", "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Total Billed Amount", + "label": "Total Billed Hours", "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 1, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_costing_amount", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Total Costing Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -651,25 +677,51 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "total_costing_amount", + "fieldname": "total_billed_amount", "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Total Costing Amount", + "label": "Total Billed Amount", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "per_billed", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "% Amount Billed", "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -765,7 +817,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-09-07 06:48:27.316087", + "modified": "2016-09-08 06:35:06.943066", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index 68a8f4d555..867603b0a9 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -25,10 +25,12 @@ class Timesheet(Document): self.validate_time_logs() self.update_cost() self.calculate_total_amounts() + self.calculate_percentage_billed() def calculate_total_amounts(self): self.total_hours = 0.0 self.total_billing_hours = 0.0 + self.total_billed_hours = 0.0 self.total_billing_amount = 0.0 self.total_costing_amount = 0.0 self.total_billed_amount = 0.0 @@ -37,11 +39,17 @@ class Timesheet(Document): self.update_billing_hours(d) self.total_hours += flt(d.hours) - self.total_billing_hours += flt(d.billing_hours) - if d.billable: + if d.billable: + self.total_billing_hours += flt(d.billing_hours) self.total_billing_amount += flt(d.billing_amount) self.total_costing_amount += flt(d.costing_amount) - self.total_billed_amount += flt(d.billed_amount) + self.total_billed_amount += flt(d.billing_amount) if d.sales_invoice else 0.0 + self.total_billed_hours += flt(d.billing_hours) if d.sales_invoice else 0.0 + + def calculate_percentage_billed(self): + self.per_billed = 0 + if self.total_billed_amount > 0 and self.total_billing_amount > 0: + self.per_billed = (self.total_billed_amount * 100) / self.total_billing_amount def update_billing_hours(self, args): if cint(args.billing_hours) == 0: @@ -54,7 +62,7 @@ class Timesheet(Document): "2": "Cancelled" }[str(self.docstatus or 0)] - if self.sales_invoice: + if self.per_billed == 100: self.status = "Billed" if self.salary_slip: @@ -253,9 +261,9 @@ def get_projectwise_timesheet_data(project, parent=None): if parent: cond = "and parent = %(parent)s" - return frappe.db.sql("""select parent, billing_hours, (billing_amount - billed_amount) as billing_amt + return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt from `tabTimesheet Detail` where docstatus=1 and project = %(project)s {0} - having billing_amt > 0""".format(cond), {'project': project, 'parent': parent}, as_dict=1) + and sales_invoice is null""".format(cond), {'project': project, 'parent': parent}, as_dict=1) @frappe.whitelist() def get_timesheet(doctype, txt, searchfield, start, page_len, filters): @@ -266,30 +274,41 @@ def get_timesheet(doctype, txt, searchfield, start, page_len, filters): condition = "and tsd.project = %(project)s" return frappe.db.sql("""select distinct tsd.parent from `tabTimesheet Detail` tsd, - `tabTimesheet` ts where ts.status in ('Submitted', 'Payslip') and - (tsd.billing_amount - tsd.billed_amount) > 0 and - tsd.docstatus = 1 and tsd.parent LIKE %(txt)s {condition} + `tabTimesheet` ts where + ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and + tsd.docstatus = 1 and ts.total_billing_amount > 0 + and tsd.parent LIKE %(txt)s {condition} order by tsd.parent limit %(start)s, %(page_len)s""" .format(condition=condition), { "txt": "%%%s%%" % frappe.db.escape(txt), "start": start, "page_len": page_len, 'project': filters.get("project") }) +@frappe.whitelist() +def get_timesheet_data(name, project): + if project and project!='': + data = get_projectwise_timesheet_data(project, name) + else: + data = frappe.get_all('Timesheet', + fields = ["(total_billing_amount - total_billed_amount) as billing_amt", "total_billing_hours as billing_hours"], filters = {'name': name}) + + return { + 'billing_hours': data[0].billing_hours, + 'billing_amount': data[0].billing_amt, + 'timesheet_detail': data[0].name if project and project!= '' else None + } + @frappe.whitelist() def make_sales_invoice(source_name, target=None): target = frappe.new_doc("Sales Invoice") + timesheet = frappe.get_doc('Timesheet', source_name) + + target.append('timesheets', { + 'time_sheet': timesheet.name, + 'billing_hours': flt(timesheet.total_billing_hours) - flt(timesheet.total_billed_hours), + 'billing_amount': flt(timesheet.total_billing_amount) - flt(timesheet.total_billed_amount) + }) - target.append("timesheets", get_mapped_doc("Timesheet", source_name, { - "Timesheet": { - "doctype": "Sales Invoice Timesheet", - "field_map": { - "total_billing_amount": "billing_amount", - "total_billing_hours": "billing_hours", - "name": "time_sheet" - }, - } - })) - target.run_method("calculate_billing_amount_from_timesheet") return target @@ -330,7 +349,7 @@ def get_activity_cost(employee=None, activity_type=None): ["costing_rate", "billing_rate"], as_dict=True) return rate[0] if rate else {} - + @frappe.whitelist() def get_events(start, end, filters=None): """Returns events for Gantt / Calendar view rendering. diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json index 560ce9f7a8..300fed30d5 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json @@ -377,33 +377,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "billed_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Billed Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -618,6 +591,59 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reference", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Reference", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sales_invoice", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Invoice", + "length": 0, + "no_copy": 1, + "options": "Sales Invoice", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -630,7 +656,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-09-07 02:55:22.545715", + "modified": "2016-09-08 03:24:26.221661", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet Detail", From c940440fbe1c24b5e75455b718fff5fd49e73427 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 9 Sep 2016 13:08:23 +0530 Subject: [PATCH 4/9] patch and rearrangement of fields --- erpnext/patches.txt | 5 +- ..._invoice_from_parent_to_child_timesheet.py | 20 + .../projects/doctype/timesheet/timesheet.js | 1 + .../projects/doctype/timesheet/timesheet.json | 20 +- .../timesheet_detail/timesheet_detail.json | 676 ++++++++++-------- 5 files changed, 410 insertions(+), 312 deletions(-) create mode 100644 erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 0706a2cd01..d38ed3476a 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -295,7 +295,7 @@ erpnext.patches.v7_0.rename_prevdoc_fields erpnext.patches.v7_0.rename_time_sheet_doctype execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time") erpnext.patches.v7_0.make_is_group_fieldtype_as_check -execute:frappe.reload_doc('projects', 'doctype', 'timesheet', force=True) #2016-08-23 +execute:frappe.reload_doc('projects', 'doctype', 'timesheet') #2016-09-09 execute:frappe.delete_doc_if_exists("Report", "Employee Holiday Attendance") execute:frappe.delete_doc_if_exists("DocType", "Payment Tool") execute:frappe.delete_doc_if_exists("DocType", "Payment Tool Detail") @@ -323,4 +323,5 @@ erpnext.patches.v7_0.update_missing_employee_in_timesheet erpnext.patches.v7_0.update_status_for_timesheet erpnext.patches.v7_0.set_party_name_in_payment_entry erpnext.patches.v7_1.set_student_guardian -erpnext.patches.v7_0.update_conversion_factor_in_supplier_quotation_item \ No newline at end of file +erpnext.patches.v7_0.update_conversion_factor_in_supplier_quotation_item +erpnext.patches.v7_1.move_sales_invoice_from_parent_to_child_timesheet \ No newline at end of file diff --git a/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py b/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py new file mode 100644 index 0000000000..67e88e60ab --- /dev/null +++ b/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py @@ -0,0 +1,20 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('projects', 'doctype', 'timesheet_detail') + frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') + + frappe.db.sql(""" update + `tabTimesheet` as ts, + (select + sum(billing_amount) as billing_amount, sum(billing_hours) as billing_hours, time_sheet + from `tabSales Invoice Timesheet` where docstatus = 1 group by time_sheet + ) as sit + set + ts.total_billed_amount = sit.billing_amount, ts.total_billed_hours = sit.billing_hours, + ts.per_billed = ((sit.billing_amount * 100)/ts.total_billing_amount) + where ts.name = sit.time_sheet and ts.docstatus = 1""") + + frappe.db.sql(""" update `tabTimesheet Detail` tsd, `tabTimesheet` ts set tsd.sales_invoice = ts.sales_invoice + where tsd.parent = ts.name and ts.sales_invoice is not null""") \ No newline at end of file diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index a47b4ac44a..2160fa96f5 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -44,6 +44,7 @@ frappe.ui.form.on("Timesheet", { if(frm.doc.per_billed > 0) { cur_frm.fields_dict["time_logs"].grid.toggle_enable("billing_hours", false); + cur_frm.fields_dict["time_logs"].grid.toggle_enable("billable", false); } }, diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index caa3e7e1b0..f58610a97d 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -571,7 +571,7 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, @@ -587,9 +587,9 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -597,7 +597,7 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, @@ -613,7 +613,7 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "report_hide": 0, @@ -703,7 +703,7 @@ "unique": 0 }, { - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, @@ -716,12 +716,12 @@ "in_list_view": 0, "label": "% Amount Billed", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -817,7 +817,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-09-08 06:35:06.943066", + "modified": "2016-09-09 03:53:17.544760", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json index 300fed30d5..b1d32329ac 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.json @@ -138,245 +138,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 1, - "depends_on": "", - "fieldname": "billable", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Bill", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "billable", - "fieldname": "section_break_11", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "billing_hours", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Billing Hours", - "length": 0, - "no_copy": 0, - "permlevel": 1, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "billing_rate", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Billing Rate", - "length": 0, - "no_copy": 0, - "permlevel": 1, - "precision": "2", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "costing_rate", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Costing Rate", - "length": 0, - "no_copy": 0, - "permlevel": 1, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "", - "description": "", - "fieldname": "billing_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Billing Amount", - "length": 0, - "no_copy": 0, - "permlevel": 1, - "precision": "2", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "description": "", - "fieldname": "costing_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Costing Amount", - "length": 0, - "no_copy": 0, - "permlevel": 1, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -429,55 +190,28 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "project", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Project", - "length": 0, - "no_copy": 0, - "options": "Project", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "", - "fieldname": "task", + "depends_on": "eval:parent.production_order", + "fieldname": "workstation", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Task", + "label": "Workstation", "length": 0, "no_copy": 0, - "options": "Task", + "options": "Workstation", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -509,34 +243,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:parent.production_order", - "fieldname": "workstation", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Workstation", - "length": 0, - "no_copy": 0, - "options": "Workstation", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -592,6 +298,376 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "project_details", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 3, + "fieldname": "project", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Project", + "length": 0, + "no_copy": 0, + "options": "Project", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_2", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "task", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Task", + "length": 0, + "no_copy": 0, + "options": "Task", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 1, + "depends_on": "", + "fieldname": "billable", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Bill", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_8", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "billable", + "fieldname": "billing_hours", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Billing Hours", + "length": 0, + "no_copy": 0, + "permlevel": 1, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "billable", + "fieldname": "section_break_11", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "billing_rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Billing Rate", + "length": 0, + "no_copy": 0, + "permlevel": 1, + "precision": "2", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "depends_on": "", + "description": "", + "fieldname": "billing_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Billing Amount", + "length": 0, + "no_copy": 0, + "permlevel": 1, + "precision": "2", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_14", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "costing_rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Costing Rate", + "length": 0, + "no_copy": 0, + "permlevel": 1, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "description": "", + "fieldname": "costing_amount", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Costing Amount", + "length": 0, + "no_copy": 0, + "permlevel": 1, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -656,7 +732,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-09-08 03:24:26.221661", + "modified": "2016-09-09 13:36:03.057513", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet Detail", From 1d0e8ea9c638e54dbc920a6ee85d0a665d7dc5bb Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 9 Sep 2016 15:05:17 +0530 Subject: [PATCH 5/9] minor changes --- .../sales_invoice_timesheet/sales_invoice_timesheet.json | 4 ++-- erpnext/projects/doctype/timesheet/timesheet.js | 5 ++++- erpnext/projects/doctype/timesheet/timesheet.py | 8 ++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json index e34accad9c..1191ea7153 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json @@ -96,7 +96,7 @@ "columns": 0, "fieldname": "timesheet_detail", "fieldtype": "Data", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, @@ -126,7 +126,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-09-08 05:36:00.922319", + "modified": "2016-09-09 14:01:04.095775", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 2160fa96f5..c4f92f3b63 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -156,9 +156,12 @@ var calculate_time_and_amount = function(frm) { for(var i=0; i Date: Fri, 9 Sep 2016 16:53:11 +0530 Subject: [PATCH 6/9] test cases and minor changes --- .../doctype/sales_invoice/sales_invoice.py | 24 ++++++++++++------- .../doctype/timesheet/test_timesheet.py | 19 +++++++++++---- .../projects/doctype/timesheet/timesheet.js | 8 +++++++ .../projects/doctype/timesheet/timesheet.py | 2 +- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f75a9af8ab..2e38927c7d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -85,7 +85,7 @@ class SalesInvoice(SellingController): self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items") self.update_packing_list() self.set_billing_hours_and_amount() - self.calculate_billing_amount_from_timesheet() + self.update_timesheet_billing_for_project() def before_save(self): set_account_for_mode_of_payment(self) @@ -467,13 +467,11 @@ class SalesInvoice(SellingController): if not timesheet.billing_amount and ts_doc.total_billing_amount: timesheet.billing_amount = ts_doc.total_billing_amount - def calculate_billing_amount_from_timesheet(self): - total_billing_amount = 0.0 - for data in self.timesheets: - if data.billing_amount: - total_billing_amount += data.billing_amount - - self.total_billing_amount = total_billing_amount + def update_timesheet_billing_for_project(self): + if not self.timesheets and self.project: + self.add_timesheet_data() + else: + self.calculate_billing_amount_for_timesheet() def add_timesheet_data(self): self.set('timesheets', []) @@ -486,7 +484,15 @@ class SalesInvoice(SellingController): 'timesheet_detail': data.name }) - self.calculate_billing_amount_from_timesheet() + self.calculate_billing_amount_for_timesheet() + + def calculate_billing_amount_for_timesheet(self): + total_billing_amount = 0.0 + for data in self.timesheets: + if data.billing_amount: + total_billing_amount += data.billing_amount + + self.total_billing_amount = total_billing_amount def get_warehouse(self): user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile` diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 8e7e562442..1e7be41d59 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -9,11 +9,12 @@ import datetime from frappe.utils import now_datetime, nowdate from erpnext.projects.doctype.timesheet.timesheet import OverlapError from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_sales_invoice +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice class TestTimesheet(unittest.TestCase): def test_timesheet_billing_amount(self): salary_structure = make_salary_structure("_T-Employee-0001") - timesheet = make_timesheet("_T-Employee-0001", True) + timesheet = make_timesheet("_T-Employee-0001", simulate = True, billable=1) self.assertEquals(timesheet.total_hours, 2) self.assertEquals(timesheet.total_billing_hours, 2) @@ -22,7 +23,7 @@ class TestTimesheet(unittest.TestCase): def test_salary_slip_from_timesheet(self): salary_structure = make_salary_structure("_T-Employee-0001") - timesheet = make_timesheet("_T-Employee-0001", simulate = True) + timesheet = make_timesheet("_T-Employee-0001", simulate = True, billable=1) salary_slip = make_salary_slip(timesheet.name) salary_slip.submit() @@ -51,11 +52,20 @@ class TestTimesheet(unittest.TestCase): item.rate = 100 sales_invoice.submit() - timesheet = frappe.get_doc('Timesheet', timesheet.name) self.assertEquals(sales_invoice.total_billing_amount, 100) self.assertEquals(timesheet.status, 'Billed') + def test_timesheet_billing_based_on_project(self): + timesheet = make_timesheet("_T-Employee-0001", simulate=True, billable=1, project = '_Test Project', company='_Test Company') + sales_invoice = create_sales_invoice(do_not_save=True) + sales_invoice.project = '_Test Project' + sales_invoice.submit() + + ts = frappe.get_doc('Timesheet', timesheet.name) + self.assertEquals(ts.per_billed, 100) + self.assertEquals(ts.time_logs[0].sales_invoice, sales_invoice.name) + def make_salary_structure(employee): name = frappe.db.get_value('Salary Structure Employee', {'employee': employee}, 'parent') if name: @@ -93,7 +103,7 @@ def make_salary_structure(employee): return salary_structure -def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None): +def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test Activity Type", project=None, task=None, company=None): update_activity_type(activity_type) timesheet = frappe.new_doc("Timesheet") timesheet.employee = employee @@ -105,6 +115,7 @@ def make_timesheet(employee, simulate=False, billable = 0, activity_type="_Test timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta(hours= timesheet_detail.hours) timesheet_detail.project = project timesheet_detail.task = task + timesheet_detail.company = company or '_Test Company' for data in timesheet.get('time_logs'): if simulate: diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index c4f92f3b63..c591ccb54b 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -21,6 +21,14 @@ frappe.ui.form.on("Timesheet", { } } } + + frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() { + return{ + filters: { + 'status': frm.doc.company + } + } + } }, onload: function(frm){ diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index df87ed1bb7..9d0371e3da 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -255,7 +255,7 @@ class Timesheet(Document): data.billing_amount = data.billing_rate * hours data.costing_amount = data.costing_rate * hours -@frappe.whitelist() +@frappe.whitelist() def get_projectwise_timesheet_data(project, parent=None): cond = '' if parent: From 4eb908fc766e3cd54ebfe776c8aac6c750dd2d57 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 9 Sep 2016 19:10:45 +0530 Subject: [PATCH 7/9] Doc updated for timesheet --- .../manual/en/projects/timesheet/timesheet-against-project.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/docs/user/manual/en/projects/timesheet/timesheet-against-project.md b/erpnext/docs/user/manual/en/projects/timesheet/timesheet-against-project.md index 7460a4b9a0..a8b2a6bf18 100644 --- a/erpnext/docs/user/manual/en/projects/timesheet/timesheet-against-project.md +++ b/erpnext/docs/user/manual/en/projects/timesheet/timesheet-against-project.md @@ -8,6 +8,9 @@ Timesheets can be tracked against Project and Tasks so that you can get reports To bill Customer based on Timesheet, check "Is Billable" in the Timesheet created against Project and Task. To learn more about billing Customer from Timesheet, click [here]({{docs_base_url}}/user/manual/en/projects/timesheet/sales-invoice-from-timesheet.html). +User can also make invoice against timesheet by selecting the project on the invoice. System will fetch the records from the timesheet based on selected project, for mode detail check below video + + ####Project Costing When creating Timesheet, Employee will have to select an Activity Type. For each Activity Type, you can create an Activity Cost master. In the Activity Cost, Billing Rate and Costing rate is defined for each Employee. From 7b6fdb77d00f2cb04da557debfa587db8deecdae Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 12 Sep 2016 19:06:41 +0530 Subject: [PATCH 8/9] rename total_billing_amount to total_billable_amount in timesheet doctype --- .../doctype/sales_invoice/sales_invoice.py | 4 ++-- erpnext/demo/user/projects.py | 2 +- erpnext/patches.txt | 3 ++- ..._salesinvoiceitem_to_salesinvoicetimesheet.py | 4 ++-- ...les_invoice_from_parent_to_child_timesheet.py | 2 +- erpnext/patches/v7_1/rename_field_timesheet.py | 8 ++++++++ .../patches/v7_1/update_total_billing_hours.py | 2 +- .../projects/doctype/timesheet/test_timesheet.py | 1 + erpnext/projects/doctype/timesheet/timesheet.js | 8 ++++---- .../projects/doctype/timesheet/timesheet.json | 6 +++--- erpnext/projects/doctype/timesheet/timesheet.py | 16 ++++++++-------- 11 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 erpnext/patches/v7_1/rename_field_timesheet.py diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 2e38927c7d..99c869d809 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -464,8 +464,8 @@ class SalesInvoice(SellingController): if not timesheet.billing_hours and ts_doc.total_billing_hours: timesheet.billing_hours = ts_doc.total_billing_hours - if not timesheet.billing_amount and ts_doc.total_billing_amount: - timesheet.billing_amount = ts_doc.total_billing_amount + if not timesheet.billing_amount and ts_doc.total_billable_amount: + timesheet.billing_amount = ts_doc.total_billable_amount def update_timesheet_billing_for_project(self): if not self.timesheets and self.project: diff --git a/erpnext/demo/user/projects.py b/erpnext/demo/user/projects.py index 505ccfd077..9802447679 100644 --- a/erpnext/demo/user/projects.py +++ b/erpnext/demo/user/projects.py @@ -22,7 +22,7 @@ def make_timesheet_for_projects(current_date ): ts = make_timesheet(employee, simulate = True, billable = 1, activity_type=get_random("Activity Type"), project=data.project, task =data.name) - if flt(ts.total_billing_amount) > 0.0: + if flt(ts.total_billable_amount) > 0.0: make_sales_invoice_for_timesheet(ts.name) frappe.db.commit() diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d38ed3476a..802e045d65 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -295,7 +295,8 @@ erpnext.patches.v7_0.rename_prevdoc_fields erpnext.patches.v7_0.rename_time_sheet_doctype execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time") erpnext.patches.v7_0.make_is_group_fieldtype_as_check -execute:frappe.reload_doc('projects', 'doctype', 'timesheet') #2016-09-09 +execute:frappe.reload_doc('projects', 'doctype', 'timesheet') #2016-09-12 +erpnext.patches.v7_1.rename_field_timesheet execute:frappe.delete_doc_if_exists("Report", "Employee Holiday Attendance") execute:frappe.delete_doc_if_exists("DocType", "Payment Tool") execute:frappe.delete_doc_if_exists("DocType", "Payment Tool Detail") diff --git a/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py b/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py index 695c552f06..a365f65605 100644 --- a/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py +++ b/erpnext/patches/v7_0/move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet.py @@ -3,12 +3,12 @@ import frappe def execute(): frappe.reload_doc('accounts', 'doctype', 'sales_invoice') frappe.reload_doc('accounts', 'doctype', 'sales_invoice_payment') - for time_sheet in frappe.db.sql(""" select sales_invoice, name, total_billing_amount from `tabTimesheet` + for time_sheet in frappe.db.sql(""" select sales_invoice, name, total_billable_amount from `tabTimesheet` where sales_invoice is not null and docstatus < 2""", as_dict=True): si_doc = frappe.get_doc('Sales Invoice', time_sheet.sales_invoice) ts = si_doc.append('timesheets',{}) ts.time_sheet = time_sheet.name - ts.billing_amount = time_sheet.total_billing_amount + ts.billing_amount = time_sheet.total_billable_amount si_doc.update_time_sheet(time_sheet.sales_invoice) si_doc.flags.ignore_validate_update_after_submit = True si_doc.save() \ No newline at end of file diff --git a/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py b/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py index 67e88e60ab..d1ec7c697e 100644 --- a/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py +++ b/erpnext/patches/v7_1/move_sales_invoice_from_parent_to_child_timesheet.py @@ -13,7 +13,7 @@ def execute(): ) as sit set ts.total_billed_amount = sit.billing_amount, ts.total_billed_hours = sit.billing_hours, - ts.per_billed = ((sit.billing_amount * 100)/ts.total_billing_amount) + ts.per_billed = ((sit.billing_amount * 100)/ts.total_billable_amount) where ts.name = sit.time_sheet and ts.docstatus = 1""") frappe.db.sql(""" update `tabTimesheet Detail` tsd, `tabTimesheet` ts set tsd.sales_invoice = ts.sales_invoice diff --git a/erpnext/patches/v7_1/rename_field_timesheet.py b/erpnext/patches/v7_1/rename_field_timesheet.py new file mode 100644 index 0000000000..1957545cd3 --- /dev/null +++ b/erpnext/patches/v7_1/rename_field_timesheet.py @@ -0,0 +1,8 @@ +from __future__ import unicode_literals +import frappe +from frappe.model.utils.rename_field import rename_field + +def execute(): + doctype = 'Timesheet' + if "total_billing_amount" in frappe.db.get_table_columns(doctype): + rename_field(doctype, 'total_billing_amount', 'total_billable_amount') \ No newline at end of file diff --git a/erpnext/patches/v7_1/update_total_billing_hours.py b/erpnext/patches/v7_1/update_total_billing_hours.py index a38b88d594..68222c4274 100644 --- a/erpnext/patches/v7_1/update_total_billing_hours.py +++ b/erpnext/patches/v7_1/update_total_billing_hours.py @@ -6,7 +6,7 @@ def execute(): frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') frappe.db.sql("""update tabTimesheet set total_billing_hours=total_hours - where total_billing_amount>0 and docstatus = 1""") + where total_billable_amount>0 and docstatus = 1""") frappe.db.sql("""update `tabTimesheet Detail` set billing_hours=hours where docstatus < 2""") diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 1e7be41d59..22bb2761b0 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -20,6 +20,7 @@ class TestTimesheet(unittest.TestCase): self.assertEquals(timesheet.total_billing_hours, 2) self.assertEquals(timesheet.time_logs[0].billing_rate, 50) self.assertEquals(timesheet.time_logs[0].billing_amount, 100) + self.assertEquals(timesheet.total_billable_amount, 100) def test_salary_slip_from_timesheet(self): salary_structure = make_salary_structure("_T-Employee-0001") diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index c591ccb54b..1b6f95678d 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -25,7 +25,7 @@ frappe.ui.form.on("Timesheet", { frm.fields_dict['time_logs'].grid.get_field('project').get_query = function() { return{ filters: { - 'status': frm.doc.company + 'company': frm.doc.company } } } @@ -159,12 +159,12 @@ var calculate_time_and_amount = function(frm) { var tl = frm.doc.time_logs || []; total_working_hr = 0; total_billing_hr = 0; - total_billing_amount = 0; + total_billable_amount = 0; total_costing_amount = 0; for(var i=0; i 0 and self.total_billing_amount > 0: - self.per_billed = (self.total_billed_amount * 100) / self.total_billing_amount + if self.total_billed_amount > 0 and self.total_billable_amount > 0: + self.per_billed = (self.total_billed_amount * 100) / self.total_billable_amount def update_billing_hours(self, args): if cint(args.billing_hours) == 0: @@ -276,7 +276,7 @@ def get_timesheet(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select distinct tsd.parent from `tabTimesheet Detail` tsd, `tabTimesheet` ts where ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and - tsd.docstatus = 1 and ts.total_billing_amount > 0 + tsd.docstatus = 1 and ts.total_billable_amount > 0 and tsd.parent LIKE %(txt)s {condition} order by tsd.parent limit %(start)s, %(page_len)s""" .format(condition=condition), { @@ -290,7 +290,7 @@ def get_timesheet_data(name, project): data = get_projectwise_timesheet_data(project, name) else: data = frappe.get_all('Timesheet', - fields = ["(total_billing_amount - total_billed_amount) as billing_amt", "total_billing_hours as billing_hours"], filters = {'name': name}) + fields = ["(total_billable_amount - total_billed_amount) as billing_amt", "total_billing_hours as billing_hours"], filters = {'name': name}) return { 'billing_hours': data[0].billing_hours, @@ -306,10 +306,10 @@ def make_sales_invoice(source_name, target=None): target.append('timesheets', { 'time_sheet': timesheet.name, 'billing_hours': flt(timesheet.total_billing_hours) - flt(timesheet.total_billed_hours), - 'billing_amount': flt(timesheet.total_billing_amount) - flt(timesheet.total_billed_amount) + 'billing_amount': flt(timesheet.total_billable_amount) - flt(timesheet.total_billed_amount) }) - target.run_method("calculate_billing_amount_from_timesheet") + target.run_method("calculate_billing_amount_for_timesheet") return target From 05682387864cd3afc507aa9fee388519280e6a27 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 12 Sep 2016 23:00:24 +0530 Subject: [PATCH 9/9] rename total_billing_hours to total_billable_hours in timesheet doctype --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 4 ++-- erpnext/patches/v7_1/rename_field_timesheet.py | 7 +++++-- erpnext/patches/v7_1/update_total_billing_hours.py | 4 ++-- erpnext/projects/doctype/timesheet/test_timesheet.py | 2 +- erpnext/projects/doctype/timesheet/timesheet.js | 2 +- erpnext/projects/doctype/timesheet/timesheet.json | 6 +++--- erpnext/projects/doctype/timesheet/timesheet.py | 8 ++++---- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 99c869d809..ecc9a6026a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -461,8 +461,8 @@ class SalesInvoice(SellingController): def set_billing_hours_and_amount(self): for timesheet in self.timesheets: ts_doc = frappe.get_doc('Timesheet', timesheet.time_sheet) - if not timesheet.billing_hours and ts_doc.total_billing_hours: - timesheet.billing_hours = ts_doc.total_billing_hours + if not timesheet.billing_hours and ts_doc.total_billable_hours: + timesheet.billing_hours = ts_doc.total_billable_hours if not timesheet.billing_amount and ts_doc.total_billable_amount: timesheet.billing_amount = ts_doc.total_billable_amount diff --git a/erpnext/patches/v7_1/rename_field_timesheet.py b/erpnext/patches/v7_1/rename_field_timesheet.py index 1957545cd3..3690a2e79d 100644 --- a/erpnext/patches/v7_1/rename_field_timesheet.py +++ b/erpnext/patches/v7_1/rename_field_timesheet.py @@ -4,5 +4,8 @@ from frappe.model.utils.rename_field import rename_field def execute(): doctype = 'Timesheet' - if "total_billing_amount" in frappe.db.get_table_columns(doctype): - rename_field(doctype, 'total_billing_amount', 'total_billable_amount') \ No newline at end of file + fields_dict = {'total_billing_amount': 'total_billable_amount', 'total_billing_hours': 'total_billable_hours'} + + for old_fieldname, new_fieldname in fields_dict.items(): + if old_fieldname in frappe.db.get_table_columns(doctype): + rename_field(doctype, old_fieldname, new_fieldname) diff --git a/erpnext/patches/v7_1/update_total_billing_hours.py b/erpnext/patches/v7_1/update_total_billing_hours.py index 68222c4274..b9c96028f5 100644 --- a/erpnext/patches/v7_1/update_total_billing_hours.py +++ b/erpnext/patches/v7_1/update_total_billing_hours.py @@ -5,10 +5,10 @@ def execute(): frappe.reload_doc('projects', 'doctype', 'timesheet_detail') frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet') - frappe.db.sql("""update tabTimesheet set total_billing_hours=total_hours + frappe.db.sql("""update tabTimesheet set total_billable_hours=total_hours where total_billable_amount>0 and docstatus = 1""") frappe.db.sql("""update `tabTimesheet Detail` set billing_hours=hours where docstatus < 2""") - frappe.db.sql(""" update `tabSales Invoice Timesheet` set billing_hours = (select total_billing_hours from `tabTimesheet` + frappe.db.sql(""" update `tabSales Invoice Timesheet` set billing_hours = (select total_billable_hours from `tabTimesheet` where name = time_sheet) where time_sheet is not null""") \ No newline at end of file diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 22bb2761b0..369be6da3c 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -17,7 +17,7 @@ class TestTimesheet(unittest.TestCase): timesheet = make_timesheet("_T-Employee-0001", simulate = True, billable=1) self.assertEquals(timesheet.total_hours, 2) - self.assertEquals(timesheet.total_billing_hours, 2) + self.assertEquals(timesheet.total_billable_hours, 2) self.assertEquals(timesheet.time_logs[0].billing_rate, 50) self.assertEquals(timesheet.time_logs[0].billing_amount, 100) self.assertEquals(timesheet.total_billable_amount, 100) diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 1b6f95678d..7d0e71ae99 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -173,7 +173,7 @@ var calculate_time_and_amount = function(frm) { } } - cur_frm.set_value("total_billing_hours", total_billing_hr); + cur_frm.set_value("total_billable_hours", total_billing_hr); cur_frm.set_value("total_hours", total_working_hr); cur_frm.set_value("total_billable_amount", total_billable_amount); cur_frm.set_value("total_costing_amount", total_costing_amount); diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json index fd99e9a5af..168bc63142 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.json +++ b/erpnext/projects/doctype/timesheet/timesheet.json @@ -549,14 +549,14 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "total_billing_hours", + "fieldname": "total_billable_hours", "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, - "label": "Total Billing Hours", + "label": "Total Billable Hours", "length": 0, "no_copy": 0, "permlevel": 0, @@ -817,7 +817,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-09-12 18:35:01.578750", + "modified": "2016-09-12 13:19:22.298036", "modified_by": "Administrator", "module": "Projects", "name": "Timesheet", diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index ba5210dc69..6fbe3f0fc5 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -29,7 +29,7 @@ class Timesheet(Document): def calculate_total_amounts(self): self.total_hours = 0.0 - self.total_billing_hours = 0.0 + self.total_billable_hours = 0.0 self.total_billed_hours = 0.0 self.total_billable_amount = 0.0 self.total_costing_amount = 0.0 @@ -40,7 +40,7 @@ class Timesheet(Document): self.total_hours += flt(d.hours) if d.billable: - self.total_billing_hours += flt(d.billing_hours) + self.total_billable_hours += flt(d.billing_hours) self.total_billable_amount += flt(d.billing_amount) self.total_costing_amount += flt(d.costing_amount) self.total_billed_amount += flt(d.billing_amount) if d.sales_invoice else 0.0 @@ -290,7 +290,7 @@ def get_timesheet_data(name, project): data = get_projectwise_timesheet_data(project, name) else: data = frappe.get_all('Timesheet', - fields = ["(total_billable_amount - total_billed_amount) as billing_amt", "total_billing_hours as billing_hours"], filters = {'name': name}) + fields = ["(total_billable_amount - total_billed_amount) as billing_amt", "total_billable_hours as billing_hours"], filters = {'name': name}) return { 'billing_hours': data[0].billing_hours, @@ -305,7 +305,7 @@ def make_sales_invoice(source_name, target=None): target.append('timesheets', { 'time_sheet': timesheet.name, - 'billing_hours': flt(timesheet.total_billing_hours) - flt(timesheet.total_billed_hours), + 'billing_hours': flt(timesheet.total_billable_hours) - flt(timesheet.total_billed_hours), 'billing_amount': flt(timesheet.total_billable_amount) - flt(timesheet.total_billed_amount) })