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 2f1ecf1e432..470ea913dd0 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 bec87a50f03..a62d03ebc00 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 c4aa8548799..a15af7ddf4b 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 66680672c62..b04aeb4173b 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 9a68f9d6c39..c85a1d46008 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 e10459fcf11..571f75a61f1 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 6ebb8e75d3c..8b86fd7b8fc 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 caacfe1dffc..097097dc0ac 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 ef3477c3234..cd627cf1341 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 5375f93a998..a4cb3ae1a63 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