From 3fa0b51e5e08454455824c63aee0df205b20ff6d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 29 Jun 2016 17:57:39 +0530 Subject: [PATCH] [Fixes] Time sheet fixes and changed timesheets to time_logs --- .../doctype/sales_invoice/sales_invoice.py | 4 +- erpnext/hr/doctype/salary_slip/salary_slip.js | 11 ++-- erpnext/hr/doctype/salary_slip/salary_slip.py | 2 +- .../salary_structure/salary_structure.js | 16 ++++- .../salary_structure/salary_structure.json | 8 +-- .../production_order/production_order.py | 10 ++-- .../production_order/test_production_order.py | 4 +- .../v7_0/convert_timelogbatch_to_timesheet.py | 11 ++-- .../doctype/time_sheet/test_time_sheet.py | 13 +++-- .../projects/doctype/time_sheet/time_sheet.js | 58 +++++++++++-------- .../doctype/time_sheet/time_sheet.json | 44 +------------- .../projects/doctype/time_sheet/time_sheet.py | 30 +++++----- .../time_sheet_detail/time_sheet_detail.json | 5 +- 13 files changed, 100 insertions(+), 116 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 2f1ecf1e43..470ea913dd 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -237,7 +237,7 @@ class SalesInvoice(SellingController): return {"print_format": pos.get("print_format") } def update_time_sheet(self, sales_invoice): - for d in self.get("timesheets"): + for d in self.timesheets: if d.time_sheet: timesheet = frappe.get_doc("Time Sheet", d.time_sheet) timesheet.sales_invoice = sales_invoice @@ -246,7 +246,7 @@ class SalesInvoice(SellingController): timesheet.save() def validate_time_sheets_are_submitted(self): - for data in self.get("timesheets"): + for data in self.timesheets: if data.time_sheet: status = frappe.db.get_value("Time Sheet", data.time_sheet, "status") if status not in ['Submitted', 'Payslip']: diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js index bec87a50f0..a62d03ebc0 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.js +++ b/erpnext/hr/doctype/salary_slip/salary_slip.js @@ -31,13 +31,10 @@ frappe.ui.form.on("Salary Slip", { }, toggle_fields: function(frm) { - if(frm.doc.salary_slip_based_on_timesheet) { - hide_field(['fiscal_year', 'month', 'total_days_in_month', 'leave_without_pay', 'payment_days']) - unhide_field(['start_date', 'end_date', 'hourly_wages', 'timesheets']) - }else { - unhide_field(['fiscal_year', 'month', 'total_days_in_month', 'leave_without_pay', 'payment_days']) - hide_field(['start_date', 'end_date', 'hourly_wages', 'timesheets']) - } + frm.toggle_display(['start_date', 'end_date', 'hourly_wages', 'timesheets'], + cint(frm.doc.salary_slip_based_on_timesheet)==1); + frm.toggle_display(['fiscal_year', 'month', 'total_days_in_month', 'leave_without_pay', 'payment_days'], + cint(frm.doc.salary_slip_based_on_timesheet)==0); } }) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index c4aa854879..a15af7ddf4 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -83,7 +83,7 @@ class SalarySlip(TransactionBase): struct = frappe.db.sql("""select name from `tabSalary Structure` where employee=%s and is_active = 'Yes' and (from_date <= %s or from_date <= %s) - and (to_date is null or to_date >= %s or to_date >= %s)""", + and (to_date is null or to_date >= %s or to_date >= %s) order by from_date desc limit 1""", (self.employee, self.start_date, joining_date, self.end_date, relieving_date)) if not struct: diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js index 66680672c6..b04aeb4173 100755 --- a/erpnext/hr/doctype/salary_structure/salary_structure.js +++ b/erpnext/hr/doctype/salary_structure/salary_structure.js @@ -12,13 +12,27 @@ cur_frm.cscript.onload = function(doc, dt, dn){ } cur_frm.cscript.refresh = function(doc, dt, dn){ - if((!doc.__islocal) && (doc.is_active == 'Yes') && (doc.salary_slip_based_on_timesheet == 0)){ + if((!doc.__islocal) && (doc.is_active == 'Yes') && cint(doc.salary_slip_based_on_timesheet == 0)){ cur_frm.add_custom_button(__('Salary Slip'), cur_frm.cscript['Make Salary Slip'], __("Make")); cur_frm.page.set_inner_btn_group_as_primary(__("Make")); } } +frappe.ui.form.on('Salary Structure', { + refresh: function(frm) { + frm.trigger("toggle_fields") + }, + + salary_slip_based_on_timesheet: function(frm) { + frm.trigger("toggle_fields") + }, + + toggle_fields: function(frm) { + frm.toggle_display('time_sheet_earning_detail', cint(frm.doc.salary_slip_based_on_timesheet)==1); + } +}) + cur_frm.cscript['Make Salary Slip'] = function() { frappe.model.open_mapped_doc({ method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip", diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.json b/erpnext/hr/doctype/salary_structure/salary_structure.json index 9a68f9d6c3..c85a1d4600 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.json +++ b/erpnext/hr/doctype/salary_structure/salary_structure.json @@ -353,7 +353,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:!doc.__islocal", + "depends_on": "", "fieldname": "salary_slip_based_on_timesheet", "fieldtype": "Check", "hidden": 0, @@ -379,14 +379,14 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "eval:doc.salary_slip_based_on_timesheet", - "fieldname": "section_break_15", + "fieldname": "time_sheet_earning_detail", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "label": "", "length": 0, "no_copy": 0, "permlevel": 0, @@ -779,7 +779,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-06-27 16:23:16.856237", + "modified": "2016-06-29 15:41:48.243771", "modified_by": "Administrator", "module": "HR", "name": "Salary Structure", diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index e10459fcf1..571f75a61f 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -160,7 +160,7 @@ class ProductionOrder(Document): def before_submit(self): self.set_required_items() - self.make_timesheets() + self.make_time_logs() def before_cancel(self): for data in self.operations: @@ -240,7 +240,7 @@ class ProductionOrder(Document): return holidays[holiday_list] - def make_timesheets(self): + def make_time_logs(self): """Capacity Planning. Plan time logs based on earliest availablity of workstation after Planned Start Date. Time logs will be created and remain in Draft mode and must be submitted before manufacturing entry can be made.""" @@ -267,7 +267,7 @@ class ProductionOrder(Document): # validate operating hours if workstation [not mandatory] is specified self.check_operation_fits_in_working_hours(d) try: - time_sheet.validate_timesheets() + time_sheet.validate_time_logs() except OverlapError: time_sheet.move_to_next_non_overlapping_slot(d.idx) @@ -319,7 +319,7 @@ class ProductionOrder(Document): frappe.throw(_("Capacity Planning Error")) def get_start_end_time(self, time_sheet, operation_id): - for data in time_sheet.timesheets: + for data in time_sheet.time_logs: if data.operation_id == operation_id: return data.from_time, data.to_time @@ -518,7 +518,7 @@ def add_timesheet_detail(time_sheet, args): if isinstance(args, unicode): args = json.loads(args) - time_sheet.append('timesheets', args) + time_sheet.append('time_logs', args) return time_sheet @frappe.whitelist() diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py index 6ebb8e75d3..8b86fd7b8f 100644 --- a/erpnext/manufacturing/doctype/production_order/test_production_order.py +++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py @@ -89,7 +89,7 @@ class TestProductionOrder(unittest.TestCase): self.assertEqual(prod_order.name, time_sheet_doc.production_order) - self.assertEqual((prod_order.qty - d.completed_qty), sum([d.completed_qty for d in time_sheet_doc.timesheets])) + self.assertEqual((prod_order.qty - d.completed_qty), sum([d.completed_qty for d in time_sheet_doc.time_logs])) manufacturing_settings = frappe.get_doc({ "doctype": "Manufacturing Settings", @@ -106,7 +106,7 @@ class TestProductionOrder(unittest.TestCase): self.assertEqual(prod_order.operations[0].actual_operating_cost, 100) time_sheet_doc1 = make_timesheet(prod_order.name) - self.assertEqual(len(time_sheet_doc1.get('timesheets')), 0) + self.assertEqual(len(time_sheet_doc1.get('time_logs')), 0) time_sheet_doc.cancel() diff --git a/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py b/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py index caacfe1dff..097097dc0a 100644 --- a/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py +++ b/erpnext/patches/v7_0/convert_timelogbatch_to_timesheet.py @@ -9,12 +9,13 @@ def execute(): time_sheet.employee= "" time_sheet.company = frappe.db.get_single_value('Global Defaults', 'default_company') time_sheet.sales_invoice = tlb.sales_invoice - for data in tlb.time_logs: - args = get_timesheet_data(data) - add_timesheet_detail(time_sheet, args) + if tlb.get('time_logs'): + for data in tlb.time_logs: + args = get_timesheet_data(data) + add_timesheet_detail(time_sheet, args) - time_sheet.docstatus = tlb.docstatus - time_sheet.save(ignore_permissions=True) + time_sheet.docstatus = tlb.docstatus + time_sheet.save(ignore_permissions=True) def get_timesheet_data(data): time_log = frappe.get_doc('Time Log', data.time_log) diff --git a/erpnext/projects/doctype/time_sheet/test_time_sheet.py b/erpnext/projects/doctype/time_sheet/test_time_sheet.py index ef3477c323..cd627cf134 100644 --- a/erpnext/projects/doctype/time_sheet/test_time_sheet.py +++ b/erpnext/projects/doctype/time_sheet/test_time_sheet.py @@ -16,8 +16,8 @@ class TestTimeSheet(unittest.TestCase): time_sheet = make_time_sheet("_T-Employee-0001", True) self.assertEquals(time_sheet.total_hours, 2) - self.assertEquals(time_sheet.timesheets[0].billing_rate, 50) - self.assertEquals(time_sheet.timesheets[0].billing_amount, 100) + self.assertEquals(time_sheet.time_logs[0].billing_rate, 50) + self.assertEquals(time_sheet.time_logs[0].billing_amount, 100) def test_salary_slip_from_timesheet(self): salary_structure = make_salary_structure("_T-Employee-0001") @@ -58,9 +58,10 @@ class TestTimeSheet(unittest.TestCase): def make_salary_structure(employee): name = frappe.db.get_value('Salary Structure', {'employee': employee, 'salary_slip_based_on_timesheet': 1}, 'name') if name: - frappe.delete_doc('Salary Structure', name) + salary_structure = frappe.get_doc('Salary Structure', name) + else: + salary_structure = frappe.new_doc("Salary Structure") - salary_structure = frappe.new_doc("Salary Structure") salary_structure.salary_slip_based_on_timesheet = 1 salary_structure.employee = employee salary_structure.from_date = nowdate() @@ -89,14 +90,14 @@ def make_time_sheet(employee, simulate=False, billable = 0): update_activity_type("_Test Activity Type") time_sheet = frappe.new_doc("Time Sheet") time_sheet.employee = employee - time_sheet_detail = time_sheet.append('timesheets', {}) + time_sheet_detail = time_sheet.append('time_logs', {}) time_sheet_detail.billable = billable time_sheet_detail.activity_type = "_Test Activity Type" time_sheet_detail.from_time = now_datetime() time_sheet_detail.hours = 2 time_sheet_detail.to_time = time_sheet_detail.from_time + datetime.timedelta(hours= time_sheet_detail.hours) - for data in time_sheet.get('timesheets'): + for data in time_sheet.get('time_logs'): if simulate: while True: try: diff --git a/erpnext/projects/doctype/time_sheet/time_sheet.js b/erpnext/projects/doctype/time_sheet/time_sheet.js index 5375f93a99..a4cb3ae1a6 100644 --- a/erpnext/projects/doctype/time_sheet/time_sheet.js +++ b/erpnext/projects/doctype/time_sheet/time_sheet.js @@ -1,11 +1,9 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.add_fetch("activity_type", "billing_rate", "billing_rate"); - frappe.ui.form.on("Time Sheet", { setup: function(frm) { - frm.get_field('timesheets').grid.editable_fields = [ + frm.get_field('time_logs').grid.editable_fields = [ {fieldname: 'activity_type', columns: 2}, {fieldname: 'from_time', columns: 2}, {fieldname: 'hours', columns: 2}, @@ -18,7 +16,7 @@ frappe.ui.form.on("Time Sheet", { } } - frm.fields_dict['timesheets'].grid.get_field('task').get_query = function(frm, cdt, cdn) { + frm.fields_dict['time_logs'].grid.get_field('task').get_query = function(frm, cdt, cdn) { child = locals[cdt][cdn]; return{ filters: { @@ -29,7 +27,7 @@ frappe.ui.form.on("Time Sheet", { }, onload: function(frm){ - if (frm.doc.__islocal && frm.doc.timesheets) { + if (frm.doc.__islocal && frm.doc.time_logs) { frm.set_value("employee", "") calculate_time_and_amount(frm); } @@ -66,7 +64,7 @@ frappe.ui.form.on("Time Sheet", { }) frappe.ui.form.on("Time Sheet Detail", { - timesheets_remove: function(frm) { + time_logs_remove: function(frm) { calculate_time_and_amount(frm); }, @@ -94,54 +92,64 @@ frappe.ui.form.on("Time Sheet Detail", { }, billing_rate: function(frm, cdt, cdn) { - var child = locals[cdt][cdn] - if(child.hours && child.billing_rate){ - frappe.mode.set_value(cdt, cdn, 'total_billing_amount', flt(child.billing_rate * child.hours)) - } - calculate_billing_amount(frm, cdt, cdn) + calculate_billing_costing_amount(frm, cdt, cdn) }, costing_rate: function(frm, cdt, cdn) { - var child = locals[cdt][cdn] - frappe.mode.set_value(cdt, cdn, 'total_costing_amount', flt(child.costing_rate * child.hours)) - calculate_billing_amount(frm, cdt, cdn) + calculate_billing_costing_amount(frm, cdt, cdn) }, billable: function(frm, cdt, cdn) { - calculate_billing_amount(frm, cdt, cdn) + calculate_billing_costing_amount(frm, cdt, cdn) + }, + + activity_type: function(frm, cdt, cdn) { + child = locals[cdt][cdn]; + frappe.call({ + method: "erpnext.projects.doctype.time_sheet.time_sheet.get_activity_cost", + args: { + employee: frm.doc.employee, + activity_type: child.activity_type + }, + callback: function(r){ + if(r.message){ + frappe.model.set_value(cdt, cdn, 'billing_rate', r.message['billing_rate']); + frappe.model.set_value(cdt, cdn, 'costing_rate', r.message['costing_rate']); + calculate_billing_costing_amount(frm, cdt, cdn) + } + } + }) } }); calculate_end_time = function(frm, cdt, cdn){ var child = locals[cdt][cdn]; - if(!child.from_time) { - frappe.model.set_value(cdt, cdn, "from_time", frappe.datetime.now_datetime()); - } - var d = moment(child.from_time); d.add(child.hours, "hours"); frm._setting_hours = true; frappe.model.set_value(cdt, cdn, "to_time", d.format(moment.defaultDatetimeFormat)); frm._setting_hours = false; - calculate_billing_amount(frm, cdt, cdn) + calculate_billing_costing_amount(frm, cdt, cdn) } -var calculate_billing_amount = function(frm, cdt, cdn){ +var calculate_billing_costing_amount = function(frm, cdt, cdn){ child = locals[cdt][cdn] - billing_amount = 0.0 + billing_amount = costing_amount = 0.0; if(child.hours && child.billable){ - billing_amount = (child.hours * child.billing_rate) + billing_amount = (child.hours * child.billing_rate); + costing_amount = flt(child.costing_rate * child.hours); } - frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount) + frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount); + frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount); calculate_time_and_amount(frm) } var calculate_time_and_amount = function(frm) { - var tl = frm.doc.timesheets || []; + var tl = frm.doc.time_logs || []; total_hr = 0; total_billing_amount = 0; for(var i=0; i