From 8587d66fde58653657fe81dd29ad615703d168d1 Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 14 Jul 2016 20:01:54 +0530 Subject: [PATCH 01/37] Bug 282 - Manual Period End Process --- app/controllers/wkattendance_controller.rb | 10 +++ app/helpers/wkattendance_helper.rb | 94 ++++++++++++++++++++++ app/helpers/wktime_helper.rb | 79 ------------------ app/views/wkattendance/_list.html.erb | 3 + config/locales/de.yml | 4 +- config/locales/en.yml | 5 +- config/locales/fr.yml | 2 + config/locales/it.yml | 4 +- config/routes.rb | 2 + init.rb | 4 +- 10 files changed, 123 insertions(+), 84 deletions(-) diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index d3c7220a2..0f6da102a 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -44,6 +44,16 @@ def edit render :action => 'edit' end + def runPeriodEndProcess + populateWkUserLeaves + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default :action => 'index', :tab => params[:tab] + } + end + end + def update errorMsg =nil wkuserleave = nil diff --git a/app/helpers/wkattendance_helper.rb b/app/helpers/wkattendance_helper.rb index a6c7ad67f..7adfe4a2c 100644 --- a/app/helpers/wkattendance_helper.rb +++ b/app/helpers/wkattendance_helper.rb @@ -30,5 +30,99 @@ def getLeaveIssueIds end issueIds end + + def populateWkUserLeaves + leavesInfo = Setting.plugin_redmine_wktime['wktime_leave'] + leaveAccrual = Hash.new + leaveAccAfter = Hash.new + resetMonth = Hash.new + strIssueIds = "" + currentMonthStart = Date.civil(Date.today.year, Date.today.month, 1) + if !leavesInfo.blank? + leavesInfo.each do |leave| + issue_id = leave.split('|')[0].strip + strIssueIds = strIssueIds.blank? ? (strIssueIds + issue_id) : (strIssueIds + "," + issue_id) + leaveAccrual[issue_id] = leave.split('|')[1].blank? ? 0 : leave.split('|')[1].strip + leaveAccAfter[issue_id] = leave.split('|')[2].blank? ? 0 : leave.split('|')[2].strip + resetMonth[issue_id] = leave.split('|')[3].blank? ? 0 : leave.split('|')[3].strip + end + end + + deleteWkUserLeaves(nil, currentMonthStart - 1) + + joinDateCFID = !Setting.plugin_redmine_wktime['wktime_attn_join_date_cf'].blank? ? Setting.plugin_redmine_wktime['wktime_attn_join_date_cf'].to_i : 0 + + if !strIssueIds.blank? + from = currentMonthStart << 1 + to = (from >> 1) - 1 + + prev_mon_from = from << 1 + prev_mon_to = (prev_mon_from >> 1) - 1 + + defWorkTime = !Setting.plugin_redmine_wktime['wktime_default_work_time'].blank? ? Setting.plugin_redmine_wktime['wktime_default_work_time'].to_i : 8 + + qryStr = "select v2.id, v1.user_id, v1.created_on, v1.issue_id, v2.hours, ul.balance, " + + "ul.accrual_on, ul.used, ul.accrual, v3.spent_hours, c.value as join_date " + + "from (select u.id as user_id, i.issue_id, u.status, u.type, u.created_on from users u , " + + "(select id as issue_id from issues where id in (#{strIssueIds})) i) v1 " + + "left join (select max(id) as id, user_id, issue_id, sum(hours) as hours from time_entries " + + "where spent_on between '#{from}' and '#{to}' group by user_id, issue_id) v2 " + + "on v2.user_id = v1.user_id and v2.issue_id = v1.issue_id " + + "left join (select user_id, sum(hours) as spent_hours from wk_attendances " + + "where start_time between '#{from}' and '#{to}' " + + "group by user_id) v3 on v3.user_id = v1.user_id " + + "left join wk_user_leaves ul on ul.user_id = v1.user_id and ul.issue_id = v1.issue_id " + + "and ul.accrual_on between '#{prev_mon_from}' and '#{prev_mon_to}' " + + "left join custom_values c on c.customized_id = v1.user_id and c.custom_field_id = #{joinDateCFID} " + + "where v1.status = 1 and v1.type = 'User'" + + entries = TimeEntry.find_by_sql(qryStr) + if !entries.blank? + entries.each do |entry| + userJoinDate = entry.join_date.blank? ? entry.created_on.to_date : entry.join_date.to_date + yearDiff = ((Date.today - userJoinDate).to_i / 365.0) + accrualAfter = leaveAccAfter["#{entry.issue_id}"].to_f + includeAccrual = yearDiff >= accrualAfter ? true : false + accrual = leaveAccrual["#{entry.issue_id}"].to_i + + #Accrual will be given only when the user works atleast 11 days a month + if (entry.spent_hours.blank? || (!entry.spent_hours.blank? && entry.spent_hours < (defWorkTime * 11)) || !includeAccrual) + accrual = 0 + end + lastMntBalance = entry.balance.blank? ? 0 : entry.balance + lastMntAccrual = entry.accrual.blank? ? 0 : entry.accrual + no_of_holidays = lastMntBalance + lastMntAccrual #entry.balance.blank? ? entry.accrual : entry.balance + entry.accrual + if !entry.used.blank? && entry.used > 0 + no_of_holidays = no_of_holidays - entry.used + end + #Reset + lastMonth = (currentMonthStart - 1).month + if (lastMonth == resetMonth["#{entry.issue_id}"].to_i) + no_of_holidays = 0 if !no_of_holidays.blank? && no_of_holidays > 0 + end + userLeave = WkUserLeave.new + userLeave.user_id = entry.user_id + userLeave.issue_id = entry.issue_id + userLeave.balance = no_of_holidays + userLeave.accrual = accrual + userLeave.used = entry.hours.blank? ? 0 : entry.hours + userLeave.accrual_on = currentMonthStart - 1 + userLeave.save() + end + end + end + end + + def deleteWkUserLeaves(userId, accrualOn) + if !(userId.blank? || accrualOn.blank?) + WkUserLeave.where(user_id: userId).where(accrual_on: accrualOn).delete_all + elsif !accrualOn.blank? + WkUserLeave.where(accrual_on: accrualOn).delete_all + elsif !userId.blank? + WkUserLeave.where(user_id: userId).delete_all + else + WkUserLeave.delete_all + end + end end diff --git a/app/helpers/wktime_helper.rb b/app/helpers/wktime_helper.rb index 0088b09b2..6186b2858 100644 --- a/app/helpers/wktime_helper.rb +++ b/app/helpers/wktime_helper.rb @@ -844,85 +844,6 @@ def getValidUserCF(userCFHash, userCF) tmpUserCFHash end - def populateWkUserLeaves - leavesInfo = Setting.plugin_redmine_wktime['wktime_leave'] - leaveAccrual = Hash.new - leaveAccAfter = Hash.new - resetMonth = Hash.new - strIssueIds = "" - if !leavesInfo.blank? - leavesInfo.each do |leave| - issue_id = leave.split('|')[0].strip - strIssueIds = strIssueIds.blank? ? (strIssueIds + issue_id) : (strIssueIds + "," + issue_id) - leaveAccrual[issue_id] = leave.split('|')[1].blank? ? 0 : leave.split('|')[1].strip - leaveAccAfter[issue_id] = leave.split('|')[2].blank? ? 0 : leave.split('|')[2].strip - resetMonth[issue_id] = leave.split('|')[3].blank? ? 0 : leave.split('|')[3].strip - end - end - - joinDateCFID = !Setting.plugin_redmine_wktime['wktime_attn_join_date_cf'].blank? ? Setting.plugin_redmine_wktime['wktime_attn_join_date_cf'].to_i : 0 - - if !strIssueIds.blank? - from = Date.civil(Date.today.year, Date.today.month, 1) << 1 - to = (from >> 1) - 1 - - prev_mon_from = from << 1 - prev_mon_to = (prev_mon_from >> 1) - 1 - - defWorkTime = !Setting.plugin_redmine_wktime['wktime_default_work_time'].blank? ? Setting.plugin_redmine_wktime['wktime_default_work_time'].to_i : 8 - - qryStr = "select v2.id, v1.user_id, v1.created_on, v1.issue_id, v2.hours, ul.balance, " + - "ul.accrual_on, ul.used, ul.accrual, v3.spent_hours, c.value as join_date " + - "from (select u.id as user_id, i.issue_id, u.status, u.type, u.created_on from users u , " + - "(select id as issue_id from issues where id in (#{strIssueIds})) i) v1 " + - "left join (select max(id) as id, user_id, issue_id, sum(hours) as hours from time_entries " + - "where spent_on between '#{from}' and '#{to}' group by user_id, issue_id) v2 " + - "on v2.user_id = v1.user_id and v2.issue_id = v1.issue_id " + - "left join (select user_id, sum(hours) as spent_hours from wk_attendances " + - "where start_time between '#{from}' and '#{to}' " + - "group by user_id) v3 on v3.user_id = v1.user_id " + - "left join wk_user_leaves ul on ul.user_id = v1.user_id and ul.issue_id = v1.issue_id " + - "and ul.accrual_on between '#{prev_mon_from}' and '#{prev_mon_to}' " + - "left join custom_values c on c.customized_id = v1.user_id and c.custom_field_id = #{joinDateCFID} " + - "where v1.status = 1 and v1.type = 'User'" - - entries = TimeEntry.find_by_sql(qryStr) - if !entries.blank? - entries.each do |entry| - userJoinDate = entry.join_date.blank? ? entry.created_on.to_date : entry.join_date.to_date - yearDiff = ((Date.today - userJoinDate).to_i / 365.0) - accrualAfter = leaveAccAfter["#{entry.issue_id}"].to_f - includeAccrual = yearDiff >= accrualAfter ? true : false - accrual = leaveAccrual["#{entry.issue_id}"].to_i - - #Accrual will be given only when the user works atleast 11 days a month - if (entry.spent_hours.blank? || (!entry.spent_hours.blank? && entry.spent_hours < (defWorkTime * 11)) || !includeAccrual) - accrual = 0 - end - lastMntBalance = entry.balance.blank? ? 0 : entry.balance - lastMntAccrual = entry.accrual.blank? ? 0 : entry.accrual - no_of_holidays = lastMntBalance + lastMntAccrual #entry.balance.blank? ? entry.accrual : entry.balance + entry.accrual - if !entry.used.blank? && entry.used > 0 - no_of_holidays = no_of_holidays - entry.used - end - #Reset - lastMonth = (Date.civil(Date.today.year, Date.today.month, 1) - 1).month - if (lastMonth == resetMonth["#{entry.issue_id}"].to_i) - no_of_holidays = 0 if !no_of_holidays.blank? && no_of_holidays > 0 - end - userLeave = WkUserLeave.new - userLeave.user_id = entry.user_id - userLeave.issue_id = entry.issue_id - userLeave.balance = no_of_holidays - userLeave.accrual = accrual - userLeave.used = entry.hours.blank? ? 0 : entry.hours - userLeave.accrual_on = Date.civil(Date.today.year, Date.today.month, 1) - 1 - userLeave.save() - end - end - end - end - #Luna Lenardi contribution def number_currency_format_unit begin diff --git a/app/views/wkattendance/_list.html.erb b/app/views/wkattendance/_list.html.erb index d80a3abf7..f2aab12d3 100644 --- a/app/views/wkattendance/_list.html.erb +++ b/app/views/wkattendance/_list.html.erb @@ -3,6 +3,9 @@ <%= hidden_field_tag 'back_url', url_for(params) %> <% wktime_helper = Object.new.extend(WktimeHelper) %> <% if (wktime_helper.isAccountUser) %> +
+<%= link_to l(:"button_populate_leave"), url_for(:controller => controller_name, :action => 'runPeriodEndProcess', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%> +
<%= form_tag({:controller => controller_name, :action => 'index'}, :method => :get) do %>
<%= l(:label_filter_plural) %> diff --git a/config/locales/de.yml b/config/locales/de.yml index cde794395..c860a4c77 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -195,4 +195,6 @@ de: label_enable_report_module: Enable Reports label_group_non_submission_email: Target group of non submission email - error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" \ No newline at end of file + error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" + button_populate_leave: "Run Period End Process" + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 7b5ffc3d5..d7175ef37 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -196,4 +196,7 @@ en: label_enable_report_module: Enable Reports label_group_non_submission_email: Target group of non submission email - error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" \ No newline at end of file + error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" + button_populate_leave: "Run Period End Process" + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" + \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 87432d602..8e9cc2d7c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -197,3 +197,5 @@ fr: label_group_non_submission_email: Groupe destinataire du courriel de rappel error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" + button_populate_leave: "Run Period End Process" + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index 3a6b3f4ba..b174c35e7 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -193,4 +193,6 @@ it: label_enable_report_module: Enable Reports label_group_non_submission_email: Target group of non submission email - error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" \ No newline at end of file + error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" + button_populate_leave: "Run Period End Process" + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 9dee18566..4aebf5934 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -108,4 +108,6 @@ get 'wkreport/getGroupMembers', :to => 'wkreport#getGroupMembers' get 'wkreport/getMembersbyGroup', :to => 'wkreport#getMembersbyGroup' + + get 'wkattendance/runPeriodEndProcess', :to => 'wkattendance#runPeriodEndProcess' \ No newline at end of file diff --git a/init.rb b/init.rb index d21f630af..97fb8d272 100644 --- a/init.rb +++ b/init.rb @@ -248,8 +248,8 @@ def destroy scheduler2.cron cronSt do begin Rails.logger.info "==========Attendance job - Started==========" - wktime_helper = Object.new.extend(WktimeHelper) - wktime_helper.populateWkUserLeaves() + wkattn_helper = Object.new.extend(WkattendanceHelper) + wkattn_helper.populateWkUserLeaves() rescue Exception => e Rails.logger.info "Job failed: #{e.message}" end From decae72300cab745bc33ef915468d7f660291bca Mon Sep 17 00:00:00 2001 From: Karthick Date: Fri, 15 Jul 2016 13:55:53 +0530 Subject: [PATCH 02/37] Show (*) symbol in attendance report for Clocked in users. --- app/controllers/wkreport_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/wkreport_controller.rb b/app/controllers/wkreport_controller.rb index 4a11c6e66..03b9a2466 100644 --- a/app/controllers/wkreport_controller.rb +++ b/app/controllers/wkreport_controller.rb @@ -101,7 +101,7 @@ def reportattn end if !daily_entries.blank? daily_entries.each_with_index do |entry,index| - @attendance_entries[entry.user_id.to_s + '_' + entry.spent_on.to_date.strftime("%d").to_i.to_s + '_hours'] = entry.hours.is_a?(Float) ? entry.hours.round(2) : entry.hours + @attendance_entries[entry.user_id.to_s + '_' + entry.spent_on.to_date.strftime("%d").to_i.to_s + '_hours'] = entry.hours.is_a?(Float) ? entry.hours.round(2) : (entry.hours.blank? ? '*' : entry.hours) end end render :action => 'reportattn', :layout => false From 98309c09fd00616f8d3c3793b52f4f3afcc7ad3d Mon Sep 17 00:00:00 2001 From: Karthick Date: Fri, 15 Jul 2016 17:32:45 +0530 Subject: [PATCH 03/37] Spent time report like attendance report --- app/controllers/wkreport_controller.rb | 14 +++++++++++--- app/helpers/wkreport_helper.rb | 1 + app/views/wkreport/_report_index.html.erb | 2 +- assets/javascripts/index.js | 2 +- lib/wkpatch.rb | 4 +++- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/controllers/wkreport_controller.rb b/app/controllers/wkreport_controller.rb index 03b9a2466..e31606dc5 100644 --- a/app/controllers/wkreport_controller.rb +++ b/app/controllers/wkreport_controller.rb @@ -36,7 +36,7 @@ def set_filter_session end end - def reportattn + def reportattn(useSpentTime) if !params[:group_id].blank? group_id = params[:group_id] else @@ -77,10 +77,18 @@ def reportattn end if isAccountUser || User.current.admin? leave_entry = TimeEntry.where("issue_id in (#{getLeaveIssueIds}) and spent_on between '#{@from}' and '#{@to}'") - sqlStr = "select user_id,#{dateStr} as spent_on,sum(hours) as hours from wk_attendances where #{dateStr} between '#{@from}' and '#{@to}' group by user_id,#{dateStr}" + if useSpentTime + sqlStr = "select user_id,spent_on,sum(hours) as hours from time_entries where issue_id not in (#{getLeaveIssueIds}) and spent_on between '#{@from}' and '#{@to}' group by user_id,spent_on" + else + sqlStr = "select user_id,#{dateStr} as spent_on,sum(hours) as hours from wk_attendances where #{dateStr} between '#{@from}' and '#{@to}' group by user_id,#{dateStr}" + end else leave_entry = TimeEntry.where("issue_id in (#{getLeaveIssueIds}) and spent_on between '#{@from}' and '#{@to}' and user_id = #{User.current.id} " ) - sqlStr = "select user_id,#{dateStr} as spent_on,sum(hours) as hours from wk_attendances where #{dateStr} between '#{@from}' and '#{@to}' and user_id = #{User.current.id} group by user_id,#{dateStr}" + if useSpentTime + sqlStr = "select user_id,spent_on,sum(hours) as hours from time_entries where issue_id not in (#{getLeaveIssueIds}) and spent_on between '#{@from}' and '#{@to}' and user_id = #{User.current.id} group by user_id,spent_on" + else + sqlStr = "select user_id,#{dateStr} as spent_on,sum(hours) as hours from wk_attendances where #{dateStr} between '#{@from}' and '#{@to}' and user_id = #{User.current.id} group by user_id,#{dateStr}" + end end findBySql(userSqlStr) #@userlist = User.find_by_sql(userSqlStr) diff --git a/app/helpers/wkreport_helper.rb b/app/helpers/wkreport_helper.rb index 0ec52050a..8a5c4fa30 100644 --- a/app/helpers/wkreport_helper.rb +++ b/app/helpers/wkreport_helper.rb @@ -13,6 +13,7 @@ def options_for_period_select(value) def options_for_report_select(selectedRpt) options_for_select([ [l(:label_wk_attendance), 'attendance_report'], + [l(:label_time_entry_plural), 'spent_time_report'], [l(:label_wk_timesheet), 'time_report'], [l(:label_wk_expensesheet), 'expense_report']], selectedRpt) end diff --git a/app/views/wkreport/_report_index.html.erb b/app/views/wkreport/_report_index.html.erb index 36f1b940e..64a32b949 100644 --- a/app/views/wkreport/_report_index.html.erb +++ b/app/views/wkreport/_report_index.html.erb @@ -25,7 +25,7 @@ <%=h select_tag('group_id', options_for_select( [["",0]] + (@groups.collect {|p| [p.name, p.id ]}), :selected => !groupid.nil? ? groupid.to_i: 0), :onchange => "var reportDD = document.getElementById('report_type');var id = reportDD.options[reportDD.selectedIndex].value; - var needBlankOption = (id!='attendance_report' ? false : true) ; grpChanged(this, #{User.current.id}, needBlankOption);", :style=> "width:300px;") %> + var needBlankOption = ((id=='attendance_report' || id=='spent_time_report') ? true : false) ; grpChanged(this, #{User.current.id}, needBlankOption);", :style=> "width:300px;") %> <%=l(:label_member)%> diff --git a/assets/javascripts/index.js b/assets/javascripts/index.js index 2f23a68aa..33f662c69 100644 --- a/assets/javascripts/index.js +++ b/assets/javascripts/index.js @@ -252,7 +252,7 @@ function validateMember() } function reportChanged(reportDD, userid){ var id = reportDD.options[reportDD.selectedIndex].value; - var needBlankOption = (id!='attendance_report' ? false : true) ; + var needBlankOption = ((id == 'attendance_report' || id == 'spent_time_report') ? true : false) ; grpChanged(document.getElementById("group_id"), userid, needBlankOption) } diff --git a/lib/wkpatch.rb b/lib/wkpatch.rb index 7fc6c207d..398dc6d70 100644 --- a/lib/wkpatch.rb +++ b/lib/wkpatch.rb @@ -15,7 +15,9 @@ def report #Rails.logger.info("===============================") #Rails.logger.info("#{@report_params}") if params[:report_type] == 'attendance_report' - reportattn + reportattn(false) + elsif params[:report_type] == 'spent_time_report' + reportattn(true) elsif params[:report_type] == 'time_report' redirect_to action: 'time_rpt', controller: 'wktime' elsif params[:report_type] == 'expense_report' From cda75a3d4db313a49439715cb1adda11af99be18 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Thu, 21 Jul 2016 18:01:33 +0530 Subject: [PATCH 04/37] Move tabs to application menu move tabs to menus as same as project menu --- app/controllers/wkattendance_controller.rb | 3 ++ app/helpers/wktime_helper.rb | 42 +++++++++++++++------- app/views/wkattendance/clockindex.html.erb | 9 +++++ app/views/wkattendance/index.html.erb | 8 ++--- app/views/wkexpense/index.html.erb | 10 +----- app/views/wkreport/index.html.erb | 9 +---- app/views/wktime/index.html.erb | 9 +---- assets/javascripts/index.js | 8 ++--- config/locales/de.yml | 3 +- config/locales/en.yml | 1 + config/locales/fr.yml | 3 +- config/locales/it.yml | 3 +- config/routes.rb | 4 ++- init.rb | 38 +++++++++++++++++++- 14 files changed, 98 insertions(+), 52 deletions(-) create mode 100644 app/views/wkattendance/clockindex.html.erb diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 0f6da102a..7cb035aa7 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -38,6 +38,9 @@ def index findBySql(sqlStr) end + def clockindex + end + def edit sqlStr = getQueryStr + " where i.id in (#{getLeaveIssueIds}) and u.type = 'User' and u.id = #{params[:user_id]} order by i.subject" @leave_details = WkUserLeave.find_by_sql(sqlStr) diff --git a/app/helpers/wktime_helper.rb b/app/helpers/wktime_helper.rb index 6186b2858..1aa5c8e77 100644 --- a/app/helpers/wktime_helper.rb +++ b/app/helpers/wktime_helper.rb @@ -577,22 +577,23 @@ def getTimeEntryStatus(spent_on,user_id) def time_expense_tabs tabs = [ - {:name => 'wktime', :partial => 'wktime/tab_content', :label => :label_wktime} + {:name => 'leave', :partial => 'wktime/tab_content', :label => :label_wk_leave}, + {:name => 'clock', :partial => 'wktime/tab_content', :label => :label_clock} ] - if !Setting.plugin_redmine_wktime['wktime_enable_expense_module'].blank? && - Setting.plugin_redmine_wktime['wktime_enable_expense_module'].to_i == 1 - tabs[tabs.length] = {:name => 'wkexpense', :partial => 'wktime/tab_content', :label => :label_wkexpense} - end + # if !Setting.plugin_redmine_wktime['wktime_enable_expense_module'].blank? && + # Setting.plugin_redmine_wktime['wktime_enable_expense_module'].to_i == 1 + # tabs[tabs.length] = {:name => 'wkexpense', :partial => 'wktime/tab_content', :label => :label_wkexpense} + # end - if !Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].blank? && - Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].to_i == 1 - tabs[tabs.length] = {:name => 'wkattendance', :partial => 'wktime/tab_content', :label => :label_wk_attendance} - end + # if !Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].blank? && + # Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].to_i == 1 + # tabs[tabs.length] = {:name => 'wkattendance', :partial => 'wktime/tab_content', :label => :label_wk_attendance} + # end - if !Setting.plugin_redmine_wktime['wktime_enable_report_module'].blank? && - Setting.plugin_redmine_wktime['wktime_enable_report_module'].to_i == 1 - tabs[tabs.length] = {:name => 'wkreport', :partial => 'wktime/tab_content', :label => :label_report_plural} - end + # if !Setting.plugin_redmine_wktime['wktime_enable_report_module'].blank? && + # Setting.plugin_redmine_wktime['wktime_enable_report_module'].to_i == 1 + # tabs[tabs.length] = {:name => 'wkreport', :partial => 'wktime/tab_content', :label => :label_report_plural} + # end tabs end @@ -920,4 +921,19 @@ def totalhours dateStr = getConvertDateStr('start_time') (WkAttendance.where("user_id = #{User.current.id} and #{dateStr} = '#{Time.now.strftime("%Y-%m-%d")}'").sum(:hours)).round(2) end + + def showExpense + !Setting.plugin_redmine_wktime['wktime_enable_expense_module'].blank? && + Setting.plugin_redmine_wktime['wktime_enable_expense_module'].to_i == 1 + end + + def showAttendance + !Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].blank? && + Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].to_i == 1 + end + + def showReports + !Setting.plugin_redmine_wktime['wktime_enable_report_module'].blank? && + Setting.plugin_redmine_wktime['wktime_enable_report_module'].to_i == 1 + end end \ No newline at end of file diff --git a/app/views/wkattendance/clockindex.html.erb b/app/views/wkattendance/clockindex.html.erb new file mode 100644 index 000000000..27cb58546 --- /dev/null +++ b/app/views/wkattendance/clockindex.html.erb @@ -0,0 +1,9 @@ +<%= javascript_include_tag 'index', :plugin => "redmine_wktime" %> +

<%= l(:label_ta) %>

+ + +<%= render_tabs time_expense_tabs %> + diff --git a/app/views/wkattendance/index.html.erb b/app/views/wkattendance/index.html.erb index 53b7c4947..44e21e174 100644 --- a/app/views/wkattendance/index.html.erb +++ b/app/views/wkattendance/index.html.erb @@ -1,9 +1,7 @@ -

<%= l(:label_ta) %>

+

<%= l(:label_wk_attendance) %>

<%= render_tabs time_expense_tabs %> diff --git a/app/views/wkexpense/index.html.erb b/app/views/wkexpense/index.html.erb index c71da8349..26cbb4992 100644 --- a/app/views/wkexpense/index.html.erb +++ b/app/views/wkexpense/index.html.erb @@ -1,12 +1,4 @@ -

<%= l(:label_ta) %>

- - -<%= render_tabs time_expense_tabs %> +

<%= l(:label_wkexpense) %>

<%= render :partial => 'wktime/te_index' %> diff --git a/app/views/wkreport/index.html.erb b/app/views/wkreport/index.html.erb index 22696e977..3a4813e32 100644 --- a/app/views/wkreport/index.html.erb +++ b/app/views/wkreport/index.html.erb @@ -1,11 +1,4 @@ -

<%= l(:label_ta) %>

- +

<%= l(:label_report_plural) %>

-<%= render_tabs time_expense_tabs %> <%= render :partial => 'report_index' %> <% html_title(l(:label_ta)) -%> \ No newline at end of file diff --git a/app/views/wktime/index.html.erb b/app/views/wktime/index.html.erb index 0fe161585..d636d4383 100644 --- a/app/views/wktime/index.html.erb +++ b/app/views/wktime/index.html.erb @@ -1,15 +1,8 @@
-

<%= l(:label_ta) %>

+

<%= l(:label_wktime) %>

- -<%= render_tabs time_expense_tabs %> <%= render :partial => 'te_index' %> diff --git a/assets/javascripts/index.js b/assets/javascripts/index.js index 33f662c69..61bcfd373 100644 --- a/assets/javascripts/index.js +++ b/assets/javascripts/index.js @@ -213,10 +213,10 @@ function updateUserDD(itemStr, dropdown, userid, needBlankOption, skipFirst) $(document).ready(function() { - changeProp('tab-wktime',wktimeIndexUrl); - changeProp('tab-wkexpense',wkexpIndexUrl); - changeProp('tab-wkattendance',wkattnIndexUrl); - changeProp('tab-wkreport',wkReportUrl); + //changeProp('tab-wktime',wktimeIndexUrl); + //changeProp('tab-wkexpense',wkexpIndexUrl); + changeProp('tab-leave',wkattnIndexUrl); + changeProp('tab-clock',wkReportUrl); }); diff --git a/config/locales/de.yml b/config/locales/de.yml index c860a4c77..b13656fe2 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -197,4 +197,5 @@ de: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" - text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" + label_clock: clock in/out \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index d7175ef37..b0605239d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -199,4 +199,5 @@ en: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" + label_clock: clock in/out \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8e9cc2d7c..6018b6462 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -198,4 +198,5 @@ fr: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" - text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" + label_clock: clock in/out \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index b174c35e7..507d2271d 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -195,4 +195,5 @@ it: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" - text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" \ No newline at end of file + text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" + label_clock: clock in/out \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 4aebf5934..a91ccc088 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -96,7 +96,9 @@ get 'wkattendance/getIssuesByProject', :to => 'wkattendance#getIssuesByProject' - get 'wkattendance/getProjectByIssue', :to => 'wkattendance#getProjectByIssue' + get 'wkattendance/getProjectByIssue', :to => 'wkattendance#getProjectByIssue' + + get 'wkattendance/clockindex', :to => 'wkattendance#clockindex' #For Report get 'wkreport/index', :to => 'wkreport#index' diff --git a/init.rb b/init.rb index 97fb8d272..d01676525 100644 --- a/init.rb +++ b/init.rb @@ -2,6 +2,34 @@ require_dependency 'custom_fields_helper' require 'wkpatch' require 'report_params' +require_dependency '../lib/redmine/menu_manager' + + +# redmine only differs between project_menu and application_menu! but we want to display the +# time_tracker submenu only if the plugin specific controllers are called +module Redmine::MenuManager::MenuHelper + def display_main_menu?(project) + Redmine::MenuManager.items(menu_name(project)).children.present? + end + + def render_main_menu(project) + render_menu(menu_name(project), project) + end + + private + + def menu_name(project) + if project && !project.new_record? + :project_menu + else + if %w(wktime wkexpense wkattendance wkreport).include? params[:controller] + :wktime_menu + else + :application_menu + end + end + end +end module WktimeHelperPatch def self.included(base) @@ -210,6 +238,14 @@ def destroy project_module :time_tracking do permission :approve_time_entries, {:wktime => [:update]}, :require => :member end + + + Redmine::MenuManager.map :wktime_menu do |menu| + menu.push :wktime, { :controller => 'wktime', :action => 'index' }, :caption => :label_wktime, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission } + menu.push :wkexpense, { :controller => 'wkexpense', :action => 'index' }, :caption => :label_wkexpense, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission && Object.new.extend(WktimeHelper).showExpense } + menu.push :wkattendance, { :controller => 'wkattendance', :action => 'index' }, :caption => :label_wk_attendance, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission && Object.new.extend(WktimeHelper).showAttendance} + menu.push :wkreport, { :controller => 'wkreport', :action => 'index' }, :caption => :label_report_plural, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission && Object.new.extend(WktimeHelper).showReports} + end end @@ -318,7 +354,7 @@ def controller_issues_edit_before_save(context={}) end end end - render_on :view_layouts_base_content, :partial => 'wktime/attendance_widget' + render_on :view_layouts_base_content, :partial => 'wktime/attendance_widget' end From 07b5849f0baf7ecc4fcc32032605aac823dd5a11 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Tue, 2 Aug 2016 19:29:02 +0530 Subject: [PATCH 05/37] Clock in/out tab in attendance module --- app/controllers/wkattendance_controller.rb | 159 +++++++++++++++++++- app/controllers/wktime_controller.rb | 54 +------ app/helpers/wktime_helper.rb | 52 +++++++ app/views/wkattendance/_clk_index.html.erb | 46 ++++++ app/views/wkattendance/_clk_list.html.erb | 36 +++++ app/views/wkattendance/_date_range.html.erb | 33 ++++ app/views/wkattendance/clockedit.html.erb | 85 +++++++++++ app/views/wkattendance/clockindex.html.erb | 6 +- app/views/wkattendance/index.html.erb | 2 +- assets/javascripts/edit.js | 114 ++++++++++++-- assets/javascripts/index.js | 7 +- assets/javascripts/wkstatus.js | 35 +++++ config/locales/de.yml | 3 +- config/locales/en.yml | 3 +- config/locales/fr.yml | 3 +- config/locales/it.yml | 3 +- config/routes.rb | 13 +- 17 files changed, 570 insertions(+), 84 deletions(-) create mode 100644 app/views/wkattendance/_clk_index.html.erb create mode 100644 app/views/wkattendance/_clk_list.html.erb create mode 100644 app/views/wkattendance/_date_range.html.erb create mode 100644 app/views/wkattendance/clockedit.html.erb diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 7cb035aa7..ddd2fda99 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -35,10 +35,157 @@ def index if !params[:name].blank? sqlStr = sqlStr + " and (LOWER(u.firstname) like LOWER('%#{params[:name]}%') or LOWER(u.lastname) like LOWER('%#{params[:name]}%'))" end - findBySql(sqlStr) + findBySql(sqlStr, WkUserLeave) end def clockindex + @clk_entries = nil + @groups = Group.sorted.all + set_filter_session + retrieve_date_range + @members = Array.new + userIds = Array.new + userList = getGroupMembers + userList.each do |users| + @members << [users.name,users.id.to_s()] + userIds << users.id + end + ids = nil + if params[:user_id].blank? && params[:user_id] != 0 + ids = User.current.id + elsif params[:user_id].to_i != 0 && params[:group_id].to_i == 0 + ids = params[:user_id].to_i + elsif params[:group_id].to_i != 0 + ids = params[:user_id].to_i == 0 ? (userIds.blank? ? 0 : userIds.join(',')) : params[:user_id].to_i + else + ids = userIds.join(',') + end + if @from.blank? && @to.blank? + getAllTimeRange(ids, false) + end + noOfDays = 't4.i*1*10000 + t3.i*1*1000 + t2.i*1*100 + t1.i*1*10 + t0.i*1' + sqlQuery = "select vw.id as user_id, vw.firstname, vw.lastname, vw.created_on, vw.selected_date as entry_date, evw.start_time, evw.end_time, evw.hours from + (select u.id, u.firstname, u.lastname, u.created_on, v.selected_date from" + + "(select " + getAddDateStr(@from, noOfDays) + " selected_date from " + + "(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0, + (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1, + (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2, + (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3, + (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9)t4)v, + (select u.id, u.firstname, u.lastname, u.created_on from users u where u.type = 'User' ) u + WHERE v.selected_date between '#{@from}' and '#{@to}' order by u.id, v.selected_date) vw left join + (select min(start_time) as start_time, max(end_time) as end_time, " + getConvertDateStr('start_time') + " + entry_date,sum(hours) as hours, user_id from wk_attendances WHERE " + getConvertDateStr('start_time') +" between '#{@from}' and '#{@to}' + group by user_id, " + getConvertDateStr('start_time') + ") evw on (vw.selected_date = evw.entry_date and vw.id = evw.user_id)" + if params[:user_id].blank? && params[:user_id] != 0 + sqlQuery += "where vw.id in(#{User.current.id}) " + elsif params[:user_id].to_i != 0 && params[:group_id].to_i == 0 + sqlQuery += "where vw.id in(#{params[:user_id].to_i}) " + elsif params[:group_id].to_i != 0 + sqlQuery += "where vw.id in(#{params[:user_id].to_i == 0 ? (userIds.blank? ? 0 : userIds.join(',')) : params[:user_id].to_i }) " + end + findBySql(sqlQuery, WkAttendance) + end + + + def clockedit + sqlQuery = "select a.id,a.user_id, a.start_time, a.end_time, a.hours, u.firstname, u.lastname FROM users u + left join wk_attendances a on u.id = a.user_id and #{getConvertDateStr('a.start_time')} = '#{params[:date]}' where u.id = '#{params[:user_id]}' ORDER BY a.start_time" + @wkattnEntries = WkAttendance.find_by_sql(sqlQuery) + end + + def getMembersbyGroup + group_by_users="" + userList=[] + userList = getGroupMembers + userList.each do |users| + group_by_users << users.id.to_s() + ',' + users.name + "\n" + end + respond_to do |format| + format.text { render :text => group_by_users } + end + end + + def getGroupMembers + userList = nil + group_id = nil + if (!params[:group_id].blank?) + group_id = params[:group_id] + else + group_id = session[:wkattendance][:group_id] + end + + if !group_id.blank? && group_id.to_i > 0 + userList = User.in_group(group_id) + else + userList = User.order("#{User.table_name}.firstname ASC,#{User.table_name}.lastname ASC") + end + userList + end + + def set_filter_session + if params[:searchlist].blank? && session[:wkattendance].nil? + session[:wkattendance] = {:period_type => params[:period_type], :period => params[:period],:group_id => params[:group_id], :user_id => params[:user_id], :from => @from, :to => @to} + elsif params[:searchlist] =='wkattendance' + session[:wkattendance][:period_type] = params[:period_type] + session[:wkattendance][:period] = params[:period] + session[:wkattendance][:group_id] = params[:group_id] + session[:wkattendance][:user_id] = params[:user_id] + session[:wkattendance][:from] = params[:from] + session[:wkattendance][:to] = params[:to] + end + end + + # Retrieves the date range based on predefined ranges or specific from/to param dates + def retrieve_date_range + @free_period = false + @from, @to = nil, nil + period_type = session[:wkattendance][:period_type] + period = session[:wkattendance][:period] + fromdate = session[:wkattendance][:from] + todate = session[:wkattendance][:to] + if (period_type == '1' || (period_type.nil? && !period.nil?)) + case period.to_s + when 'today' + @from = @to = Date.today + when 'yesterday' + @from = @to = Date.today - 1 + when 'current_week' + @from = getStartDay(Date.today - (Date.today.cwday - 1)%7) + @to = @from + 6 + when 'last_week' + @from =getStartDay(Date.today - 7 - (Date.today.cwday - 1)%7) + @to = @from + 6 + when '7_days' + @from = Date.today - 7 + @to = Date.today + when 'current_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) + @to = Date.today #(@from >> 1) - 1 + when 'last_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 + @to = (@from >> 1) - 1 + when '30_days' + @from = Date.today - 30 + @to = Date.today + when 'current_year' + @from = Date.civil(Date.today.year, 1, 1) + @to = Date.today #Date.civil(Date.today.year, 12, 31) + end + #elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) + elsif period_type == '2' || (period_type.nil? && (!fromdate.nil? || !todate.nil?)) + begin; @from = fromdate.to_s.to_date unless fromdate.blank?; rescue; end + begin; @to = todate.to_s.to_date unless todate.blank?; rescue; end + @free_period = true + else + # default + # 'current_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) + @to = Date.today #(@from >> 1) - 1 + end + + @from, @to = @to, @from if @from && @to && @from > @to + end def edit @@ -203,12 +350,16 @@ def setLimitAndOffset end end - def findBySql(query) - result = WkUserLeave.find_by_sql("select count(*) as id from (" + query + ") as v2") + def findBySql(query, model) + result = model.find_by_sql("select count(*) as id from (" + query + ") as v2") @entry_count = result.blank? ? 0 : result[0].id setLimitAndOffset() rangeStr = formPaginationCondition() - @leave_entries = WkUserLeave.find_by_sql(query + " order by u.firstname " + rangeStr ) + if model == WkUserLeave + @leave_entries = model.find_by_sql(query + " order by u.firstname " + rangeStr ) + else + @clk_entries = model.find_by_sql(query + " order by vw.selected_date desc, vw.firstname " + rangeStr ) + end end def formPaginationCondition diff --git a/app/controllers/wktime_controller.rb b/app/controllers/wktime_controller.rb index 22fa3ad64..a0441c8dd 100644 --- a/app/controllers/wktime_controller.rb +++ b/app/controllers/wktime_controller.rb @@ -69,9 +69,8 @@ def index else ids = user_id end - if @from.blank? && @to.blank? - getAllTimeRange(ids) + getAllTimeRange(ids, true) end teQuery = getTEQuery(@from, @to, ids) query = getQuery(teQuery, ids, @from, @to, status) @@ -866,7 +865,7 @@ def updateAttendance end wkattendance.start_time = starttime wkattendance.end_time = endtime - wkattendance.hours = entryvalues[3] + wkattendance.hours = computeWorkedHours(starttime, endtime, true)#entryvalues[3] entryvalues[0] = params[:nightshift] ? '' : entryvalues[0] else wkattendance = WkAttendance.new @@ -876,12 +875,12 @@ def updateAttendance entryvalues[2] = "00:00" entryvalues[3] = oldendvalue end - entrydate = @startday + ((entryvalues[1].to_i)- 1) + entrydate = to_boolean(params[:isdate]) ? params[:startdate] : @startday + ((entryvalues[1].to_i)- 1) wkattendance.user_id = params[:user_id].to_i wkattendance.start_time = !entryvalues[2].blank? ? Time.parse("#{entrydate.to_s} #{ entryvalues[2].to_s}:00 ").localtime.to_s : '00:00' if !entryvalues[3].blank? wkattendance.end_time = Time.parse("#{entrydate.to_s} #{ entryvalues[3].to_s}:00 ").localtime.to_s - wkattendance.hours = entryvalues[4] + wkattendance.hours = computeWorkedHours(wkattendance.start_time , wkattendance.end_time, true)#entryvalues[4] end ret += '|' ret += entryvalues[1].to_s @@ -1090,18 +1089,7 @@ def getCondition(date_field, user_id, start_date, end_date=nil) [ date_field + ' BETWEEN ? AND ? AND user_id = ?', start_date, end_date, user_id] end return cond - end - - #change the date to a last day of week - def getEndDay(date) - start_of_week = getStartOfWeek - #Martin Dube contribution: 'start of the week' configuration - unless date.nil? - daylast_diff = (6 + start_of_week) - date.wday - date += (daylast_diff%7) - end - date - end + end def prevTemplate(user_id) prev_entries = nil @@ -1829,39 +1817,7 @@ def getAllWeekSql(from, to) sqlStr += (!user_cf_sql.blank? ? " AND " : " WHERE ") + " v.selected_date between '#{from}' and '#{to}' " end - def getTEAllTimeRange(ids) - teQuery = "select v.startday from (select #{getDateSqlString('t.spent_on')} as startday " + - "from time_entries t where user_id in (#{ids})) v group by v.startday order by v.startday" - teResult = TimeEntry.find_by_sql(teQuery) - end - def getUserAllTimeRange(ids) - dateStr = getConvertDateStr('min(created_on)') - usrQuery = "select (#{dateStr}) as startday from users where id in (#{ids})" - usrResult = User.find_by_sql(usrQuery) - end - - def getAllTimeRange(ids) - teResult = getTEAllTimeRange(ids) - usrResult = getUserAllTimeRange(ids) - currentWeekEndDay = getEndDay(Date.today) - @from = getStartDay(Date.today) - @to = currentWeekEndDay - if !teResult.blank? && teResult.size > 0 - @from = (teResult[0].startday).to_date - @to = (teResult[teResult.size - 1].startday).to_date + 6 - if currentWeekEndDay > @to - @to = currentWeekEndDay - end - end - if !usrResult.blank? && usrResult.size > 0 - stDate = (usrResult[0].startday) - stDate = getStartDay(stDate.to_date) if !stDate.blank? - if (!stDate.blank? && stDate < @from) - @from = stDate - end - end - end def findWkTEByCond(cond) #@wktimes = Wktime.find(:all, :conditions => cond) diff --git a/app/helpers/wktime_helper.rb b/app/helpers/wktime_helper.rb index 1aa5c8e77..7dd0848de 100644 --- a/app/helpers/wktime_helper.rb +++ b/app/helpers/wktime_helper.rb @@ -936,4 +936,56 @@ def showReports !Setting.plugin_redmine_wktime['wktime_enable_report_module'].blank? && Setting.plugin_redmine_wktime['wktime_enable_report_module'].to_i == 1 end + + def getTEAllTimeRange(ids) + teQuery = "select v.startday from (select #{getDateSqlString('t.spent_on')} as startday " + + "from time_entries t where user_id in (#{ids})) v group by v.startday order by v.startday" + teResult = TimeEntry.find_by_sql(teQuery) + end + + def getAttnAllTimeRange(ids) + dateStr = getConvertDateStr('start_time') + teQuery = "select (#{dateStr}) as startday from wk_attendances w where user_id in (#{ids}) order by #{dateStr} " + teResult = WkAttendance.find_by_sql(teQuery) + end + + def getUserAllTimeRange(ids) + dateStr = getConvertDateStr('min(created_on)') + usrQuery = "select (#{dateStr}) as startday from users where id in (#{ids})" + usrResult = User.find_by_sql(usrQuery) + end + + #This function used in Time & Attendance Module + def getAllTimeRange(ids, isTime) + teResult = isTime ? getTEAllTimeRange(ids) : getAttnAllTimeRange(ids) + usrResult = getUserAllTimeRange(ids) + currentWeekEndDay = getEndDay(Date.today) + @from = getStartDay(Date.today) + @to = currentWeekEndDay + if !teResult.blank? && teResult.size > 0 + @from = (teResult[0].startday).to_date + @to = (teResult[teResult.size - 1].startday).to_date + 6 + if currentWeekEndDay > @to + @to = currentWeekEndDay + end + end + if !usrResult.blank? && usrResult.size > 0 + stDate = (usrResult[0].startday) + stDate = getStartDay(stDate.to_date) if !stDate.blank? && isTime + if (!stDate.blank? && stDate < @from) + @from = stDate + end + end + end + + #change the date to a last day of week + def getEndDay(date) + start_of_week = getStartOfWeek + #Martin Dube contribution: 'start of the week' configuration + unless date.nil? + daylast_diff = (6 + start_of_week) - date.wday + date += (daylast_diff%7) + end + date + end end \ No newline at end of file diff --git a/app/views/wkattendance/_clk_index.html.erb b/app/views/wkattendance/_clk_index.html.erb new file mode 100644 index 000000000..16d6bed17 --- /dev/null +++ b/app/views/wkattendance/_clk_index.html.erb @@ -0,0 +1,46 @@ +<%= javascript_include_tag 'index', :plugin => "redmine_wktime" %> +<%= stylesheet_link_tag 'wk-time', :plugin => "redmine_wktime" %> + +<%= hidden_field_tag 'back_url', url_for(params) %> +<% wktime_helper = Object.new.extend(WktimeHelper) %> + <%= form_tag({:controller => controller_name, :action => 'clockindex'}, :method => :get, :id => 'query_form') do %> + <%=h hidden_field_tag('tab', "clock") %> + <%= hidden_field_tag "searchlist", "#{controller_name}" %> + <% groupid =session[:wkattendance][:group_id] + userid =session[:wkattendance][:user_id] %> +
+ + <% if User.current.admin? || isAccountUser %> + + + <% if !@groups.blank? %> + + <% end %> + + + + <% end %> +
<%=l(:label_group_plural)%> + <%=h select_tag('group_id', + options_for_select( [["",0]] + (@groups.collect {|p| [p.name, p.id ]}), + :selected => !groupid.nil? ? groupid.to_i: 0), :onchange => "grpChanged(this, #{User.current.id}, true);", :style=> "width:300px;") %> + <%=l(:label_member)%> + <%# show the blank value if more than one user is in the list %> + <%=h select_tag('user_id', + options_for_select( [["All Users","0"]] + @members, + :selected => userid.nil? ? (@user.nil? ? User.current.id : @user.id) : userid), + :style=> "width:200px;") %>
+ + <%= render :partial => 'wkattendance/date_range' %> +
+ <% end %> +  + +<%= render :partial => 'wkattendance/clk_list'%> +<%= pagination_links_full @entry_pages, @entry_count %> +<%=h hidden_field_tag('tab', "#{controller_name}") %> diff --git a/app/views/wkattendance/_clk_list.html.erb b/app/views/wkattendance/_clk_list.html.erb new file mode 100644 index 000000000..ebb5cf3b9 --- /dev/null +++ b/app/views/wkattendance/_clk_list.html.erb @@ -0,0 +1,36 @@ +<%= stylesheet_link_tag 'wk-time', :plugin => "redmine_wktime" %> +<%= form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
+ + + + + + + + + + + + +<% @clk_entries.each do |entry| %> +<% if (Date.parse entry.entry_date).past? || (Date.parse entry.entry_date).today? %> + <%= !entry.start_time ? "user locked" : "" %>" > + + + + + + + +<% end %> +<% end %> + +
<%= l(:field_user) %><%= l(:field_start_date) %><%= l(:label_clock_in) %><%= l(:label_clock_out) %><%= l(:label_hours) %>
<%=h entry.firstname %><%=h entry.entry_date %><%=h !entry.start_time ? "" : entry.start_time.localtime.strftime('%r') %><%=h !entry.end_time ? "" : entry.end_time.localtime.strftime('%r') %><%=h !entry.hours ? "" : entry.hours %> + <%= link_to image_tag('edit.png'), {:controller => controller.controller_name, :action => 'clockedit', :user_id => entry.user_id, :date => entry.entry_date, :tab => controller.controller_name}, + :title => l(:button_edit) %> + +
+
+<% end -%> \ No newline at end of file diff --git a/app/views/wkattendance/_date_range.html.erb b/app/views/wkattendance/_date_range.html.erb new file mode 100644 index 000000000..d52115764 --- /dev/null +++ b/app/views/wkattendance/_date_range.html.erb @@ -0,0 +1,33 @@ +<%= stylesheet_link_tag 'wk-time', :plugin => "redmine_wktime" %> +
+<%= l(:label_date_range) %> +
+<% period = session[:wkattendance][:period] %> +
+<%= radio_button_tag 'period_type', '1', !@free_period, :onclick => '$("#from,#to").attr("disabled", true);$("#period").removeAttr("disabled");' %> +<%= select_tag 'period', options_for_period_select(period), + :onchange => 'this.form.submit();', + :onfocus => '$("period_type_1").checked = true;', + :disabled => @free_period %> +
+
+<%= radio_button_tag 'period_type', '2', @free_period, :onclick => '$("#from,#to").removeAttr("disabled");$("#period").attr("disabled", true);' %> + +<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), + :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))).html_safe %> + +
+
+<% if action_name =='reportdetail' || action_name =='report' %> +<%=h hidden_field_tag('control', "#{action_name}") %> +<% end %> +
+
+ +

+ <%= link_to_function l(:button_apply), '$("#query_form").submit(); return false;', :class => 'icon icon-checked' %> + <%#= link_to l(:button_apply), {:controller => controller_name, :action => action_name}, :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), {:controller => controller_name, :action => action_name, :tab => 'clock'}, :class => 'icon icon-reload' %> + +

+ diff --git a/app/views/wkattendance/clockedit.html.erb b/app/views/wkattendance/clockedit.html.erb new file mode 100644 index 000000000..c568b729b --- /dev/null +++ b/app/views/wkattendance/clockedit.html.erb @@ -0,0 +1,85 @@ + <%= javascript_include_tag 'edit', :plugin => "redmine_wktime" %> +

<%= l(:label_clock) + " " + l(:field_summary) %>

+ + + + + + + + + + + + +
<%=l(:field_user)%><%= @wkattnEntries[0].firstname + ' ' + @wkattnEntries[0].lastname if !@wkattnEntries[0].blank? %>
<%=l(:label_wk_attn_for)%> + <%= params[:date].to_s %> +
+ <%= link_to("\xc2\xab " + l(:label_previous ), {:controller => controller.controller_name, :action => 'clockedit', :user_id => params[:user_id], :date => (Date.parse params[:date])-1, :tab => controller.controller_name}, + :title => l(:label_wk_prev_week_tip)) %> + <% datetime = DateTime.now %> + <% if (Date.parse params[:date]).past? %> + | + <%= link_to(l(:label_next) + " \xc2\xbb", {:controller => controller.controller_name, :action => 'clockedit', :user_id => params[:user_id], :date => (Date.parse params[:date])+1, :tab => controller.controller_name}, + :title => l(:label_wk_next_week_tip)) %> + <%end%> +
+
+ +
+
+ + + + + + + + + + <% entry_id = Array.new %> + <% start_time = Array.new %> + <% end_time = Array.new %> + <% hours = Array.new %> + <% @wkattnEntries.each do |entry| %> + <% entry_id << entry.id %> + <% start_time << (entry.start_time.blank? ? '' : entry.start_time.localtime.strftime('%R')) %> + <% end_time << (entry.end_time.blank? ? '' : entry.end_time.localtime.strftime('%R')) %> + <% hours << entry.hours %> + <% end %> + <%=h hidden_field_tag("break_time" , Setting.plugin_redmine_wktime['wktime_break_time'] ) %> + <%=h hidden_field_tag('attnDayEntriesCnt', start_time.blank? ? 1 : start_time.length) %> + <%=h hidden_field_tag('startdate', params[:date] ) %> + <%=h hidden_field_tag('user_id', params[:user_id] ) %> + <% j = 0 %> + <% totalhours = 0 %> + <% loop do %> + "> + <%=h hidden_field_tag("attnEntriesId#{j}", (entry_id.blank? ? "" : entry_id[j]) ) %> + + + + <% totalhours += hours.blank? ? 0 : hours[j].to_f %> + <% break if j == start_time.length-1 || start_time.blank? %> + <% j += 1 %> + + <% end %> + " > + + + +
<%= l(:label_clock_in) %><%= l(:label_clock_out) %><%= l(:label_hours) %>
<%=h text_field_tag("attnstarttime#{j}", start_time.blank? ? "" : start_time[j] ,:onchange => "#{} ", :size => 10, :disabled => isAccountUser ? false : true, :required => true, :onchange => "validateHr(this,#{(j)}, ['attnstarttime#{j}', 'attnendtime#{j}', 'hoursdiff#{j}', #{true}]);") %> + <%=h text_field_tag("attnendtime#{j}", end_time.blank? ? "" : end_time[j],:size => 10, :disabled => isAccountUser ? false : true, :required => true, :onchange => "validateHr(this,#{(j)}, ['attnstarttime#{j}', 'attnendtime#{j}', 'hoursdiff#{j}', #{true}]);") %> + <%=h text_field_tag("hoursdiff#{j}", hours.blank? ? 0 : hours[j].to_f,:size => 10, :disabled => isAccountUser ? false : true, :required => true) %> +
<%=h text_field_tag("tothours", totalhours.round(2),:size => 10, :disabled => isAccountUser ? false : true, :required => true) %> +
+ + <% if isAccountUser %> + + <% end %> + +
+

+ <%= submit_tag l(:button_save), :onclick => " updateAttendance();", :hidden => isAccountUser ? false : true, :id => 'wkattendance_save', :disabled => false %>

+
+
\ No newline at end of file diff --git a/app/views/wkattendance/clockindex.html.erb b/app/views/wkattendance/clockindex.html.erb index 27cb58546..b35d2fb09 100644 --- a/app/views/wkattendance/clockindex.html.erb +++ b/app/views/wkattendance/clockindex.html.erb @@ -1,9 +1,9 @@ <%= javascript_include_tag 'index', :plugin => "redmine_wktime" %> -

<%= l(:label_ta) %>

+

<%= l(:label_wk_attendance) %>

<%= render_tabs time_expense_tabs %> - +<%= render :partial => 'wkattendance/clk_index'%> diff --git a/app/views/wkattendance/index.html.erb b/app/views/wkattendance/index.html.erb index 44e21e174..548e82cda 100644 --- a/app/views/wkattendance/index.html.erb +++ b/app/views/wkattendance/index.html.erb @@ -1,7 +1,7 @@

<%= l(:label_wk_attendance) %>

<%= render_tabs time_expense_tabs %> diff --git a/assets/javascripts/edit.js b/assets/javascripts/edit.js index b362e1ccf..df43d1dda 100644 --- a/assets/javascripts/edit.js +++ b/assets/javascripts/edit.js @@ -1113,7 +1113,7 @@ function getTotalTime(day, element) minDiff += getMinDiff(day, ['attnstarttime'+day+'_' + j,'attnendtime'+day+'_' + j, 'hoursdiff'+day+'_' + j]); } totTime = timeFormat(minDiff); - totTime = calculatebreakTime(totTime, day, element); + totTime = calculatebreakTimeNew(totTime, day, element); if(element[0] == "start_"+day) { totTime = document.getElementById(element[2]).value; @@ -1159,7 +1159,7 @@ function getMinutes(day,str) else{ if(day != -1) { - fldVal = ( str ? document.getElementById(str).value : ""); + fldVal = ( str ? (document.getElementById(str) != null ? document.getElementById(str).value : "") : ""); } else{ fldVal = str; @@ -1180,11 +1180,10 @@ function getMinutes(day,str) //Calculates and fills the total hr function updateTotalHr(day, element) { - var issueTable = document.getElementById("issueTable"); - var totTimeRow = issueTable.rows[3]; + var issueTable = document.getElementById("issueTable"); var tot_Hr = 0,tot_min = 0,totTime=""; var minDiff = 0 ; - var attnDayEntriesCnt1 = document.getElementById('attnDayEntriesCnt_'+day) != null ? document.getElementById('attnDayEntriesCnt_'+day).value : -1; + var attnDayEntriesCnt1 = document.getElementById('attnDayEntriesCnt_'+day) != null ? document.getElementById('attnDayEntriesCnt_'+day).value : (document.getElementById('attnDayEntriesCnt') != null ? document.getElementById('attnDayEntriesCnt').value : -1); if(!element) { for(j = 0 ; j < attnDayEntriesCnt1 ; j++ ) @@ -1200,7 +1199,7 @@ function updateTotalHr(day, element) } totTime = timeFormat(minDiff); - totTime = calculatebreakTime(totTime, day, element); + totTime = calculatebreakTimeNew(totTime, day, element); if(element[0] == "start_"+day) { var addtotal = document.getElementById(element[2]).value; @@ -1222,7 +1221,7 @@ function updateTotalHr(day, element) minDiff += getMinDiff(day, ['attnstarttime'+day+'_' + j,'attnendtime'+day+'_' + j, 'hoursdiff'+day+'_' + j]); } totTime = timeFormat(minDiff); - totTime = calculatebreakTime(totTime, day, element); + totTime = calculatebreakTimeNew(totTime, day, element); } if(document.getElementById("grandTotal_"+day) != null) { @@ -1235,8 +1234,21 @@ function updateTotalHr(day, element) document.getElementById("grandTotal_"+day).value = thours; //timeStringToFloat(totTime) ; totTime = convertHoursToMin(thours); } - totHrCell = totTimeRow.cells[hStartIndex + day]; - totHrCell.innerHTML = totTime + " "; + if(element[3] != null && element[3]) + { + totvalues = 0; + for(j = 0 ; j < attnDayEntriesCnt1 ; j++ ) + { + totvalues = totvalues + parseFloat(document.getElementById("hoursdiff"+j).value); + } + document.getElementById("tothours").value = totvalues; + } + else{ + var totTimeRow = issueTable.rows[3]; + totHrCell = totTimeRow.cells[hStartIndex + day]; + totHrCell.innerHTML = totTime + " "; + } + } function convertHoursToMin(thours) @@ -1273,11 +1285,15 @@ function validateHr(hrFld,day, element) } else { - - if(document.getElementById(element[1]).value) + if(element[3] != null && element[3] ) + { + updateTotalHr((day+1), element); + //updateRemainingHr((day+1), element); + } + else { updateTotalHr((day+1), element); - updateRemainingHr((day+1), element); + updateRemainingHr((day+1), element); } } @@ -1424,7 +1440,7 @@ function updateClockInOut(entrytime, strid, id, elementend){ } hoursdiff = getMinDiff(id, ""); hoursdiff = timeFormat(hoursdiff); - hoursdiff = calculatebreakTime(hoursdiff, id, ""); + hoursdiff = calculatebreakTimeNew(hoursdiff, id, ""); hours = timeStringToFloat(hoursdiff); } if(updateendvalue == "true") @@ -1432,7 +1448,7 @@ function updateClockInOut(entrytime, strid, id, elementend){ document.getElementById('end_' + (id+1)).value = elementend; nsdiff = getMinDiff((id+1), ""); nsdiff = timeFormat(nsdiff); - nsdiff = calculatebreakTime(nsdiff, (id+1), ""); + nsdiff = calculatebreakTimeNew(nsdiff, (id+1), ""); nshours = timeStringToFloat(nsdiff); } @@ -1683,14 +1699,15 @@ function updateAtt(param, diff,str,id) var datevalue = document.getElementById('startday').value; var userid = document.getElementById('user_id').value; var nightshift = false; + var date = false; if(document.getElementById('nightshift') != null && !diff ) { nightshift = document.getElementById('nightshift').value; } $.ajax({ - url: 'updateAttendance', + url: '/updateAttendance', type: 'get', - data: {editvalue : param, startdate : datevalue, user_id : userid, nightshift : nightshift}, + data: {editvalue : param, startdate : datevalue, user_id : userid, nightshift : nightshift, isdate : date}, success: function(data){ if(!diff){ hiddenClockInOut(data, str, id);}else{ newClockInOut(data); } }, }); } @@ -1732,4 +1749,69 @@ function newClockInOut(data) document.getElementById('end_' +clkdialogid).value = document.getElementById('attnendtime'+clkdialogid+"_"+(attnDayEntriesCnt-1) ).value; } +} + +function calculatebreakTimeNew(totTime, day, element){ + var startval, endval, breakStart, breakEnd, startTime, endTime, workedHours; + var breakTime = new Array(); + var breakValue = new Array(); + startval = document.getElementById(element ? element[0] : 'start_'+day).value; + endval = document.getElementById(element ? element[1] : 'end_'+day).value; + workedHours = convertTimeToSec(totTime); + + if(startval && endval) + { + startTime = convertTimeToSec(startval); + endTime = convertTimeToSec(endval); + breakTime = document.getElementById('break_time').value; + breakTime = breakTime.split(" "); + var startBTime = new Array() ,endBTime = new Array(); + if(breakTime !='') + { + for(var i= 0; i < breakTime.length ; i++) + { + breakValue = breakTime[i].split('|'); + if(breakValue[0]&&breakValue[1]&&breakValue[2]&&breakValue[3]) + { + breakStart = (breakValue[0]*3600)+(breakValue[1]*60); + breakEnd = (breakValue[2]*3600)+(breakValue[3]*60); + if(!(startTime>breakEnd || endTime < breakStart)){ + if (startTime < breakStart){ + if (endTime < breakEnd) + workedHours = workedHours - (endTime-breakStart); + else + workedHours = workedHours - (breakEnd-breakStart); + } + else{ + if (endTime > breakEnd) + workedHours = workedHours - (breakEnd-startTime); + else + workedHours = 0; + } + } + //startBTime[i]= breakValue[0] + ":" + breakValue[1] + ":00" ; + //endBTime[i] = breakValue[2] + ":" + breakValue[3] + ":00"; + } + } + } + } + return convertSecToTime(workedHours); +} + +function convertTimeToSec(timeval) +{ + var timeArr = timeval.split(':'); + seconds = (timeArr[0]*3600)+(timeArr[1]*60); + return seconds; +} + + + +function convertSecToTime(seconds) +{ + var d = Number(seconds); + var h = Math.floor(d / 3600); + var m = Math.floor(d % 3600 / 60); + var timeVal = ((h > 0 ? h + ":" + (m < 10 ? "0" : "") : "") + (h > 0 ? m : ("0:" + m)) ); + return timeVal; } \ No newline at end of file diff --git a/assets/javascripts/index.js b/assets/javascripts/index.js index 61bcfd373..c046fea63 100644 --- a/assets/javascripts/index.js +++ b/assets/javascripts/index.js @@ -1,4 +1,4 @@ -var wktimeIndexUrl,wkexpIndexUrl,wkattnIndexUrl,wkReportUrl,wkattnReportUrl; +var wkattnIndexUrl,wkReportUrl,clockInOutUrl; var no_user =""; var grpUrl=""; var userUrl=""; @@ -213,10 +213,8 @@ function updateUserDD(itemStr, dropdown, userid, needBlankOption, skipFirst) $(document).ready(function() { - //changeProp('tab-wktime',wktimeIndexUrl); - //changeProp('tab-wkexpense',wkexpIndexUrl); changeProp('tab-leave',wkattnIndexUrl); - changeProp('tab-clock',wkReportUrl); + changeProp('tab-clock',clockInOutUrl); }); @@ -257,7 +255,6 @@ function reportChanged(reportDD, userid){ } function grpChanged(grpDropdown, userid, needBlankOption){ - var id = grpDropdown.options[grpDropdown.selectedIndex].value; var fmt = 'text'; var userDropdown = document.getElementById("user_id"); diff --git a/assets/javascripts/wkstatus.js b/assets/javascripts/wkstatus.js index c321fb633..cd7318aec 100644 --- a/assets/javascripts/wkstatus.js +++ b/assets/javascripts/wkstatus.js @@ -153,6 +153,41 @@ function showIssueMessage(data,divID) { } } +function updateAttendance() +{ + var attnEntriesId, attnStartTime, attnEndTime, attnhours; + var attnDayEntriesCnt = new Array(); + var paramval = ""; + var j; + attnDayEntriesCnt = document.getElementById('attnDayEntriesCnt') != null ? document.getElementById('attnDayEntriesCnt').value : -1; + for(j = 0; j < attnDayEntriesCnt ; j++) + { + + attnEntriesId = document.getElementById('attnEntriesId'+ j); + attnStartTime = document.getElementById('attnstarttime'+ j); + attnEndTime = document.getElementById('attnendtime'+ j); + if (attnStartTime.defaultValue != attnStartTime.value || attnEndTime.defaultValue != attnEndTime.value ) { + paramval += ( !attnEntriesId.value ? (( "|" + "" ) + "|") : (attnEntriesId.value + "|") ) + (!attnStartTime.value ? "0:00" : attnStartTime.value) + "|" + (!attnEndTime.value ? "0:00" : attnEndTime.value) + ","; + if(!attnStartTime.value && !attnEndTime.value) + { + document.getElementById('attnEntriesId'+ j).value = ''; + } + } + + } + var datevalue = document.getElementById('startdate').value; + var userid = document.getElementById('user_id').value; + var nightshift = false; + var date = true; + + $.ajax({ + url: '/updateAttendance', + type: 'get', + data: {editvalue : paramval, user_id:userid, startdate : datevalue, nightshift : nightshift, isdate : date}, + success: function(data){ }, + }); +} + function signAttendance(str) { diff --git a/config/locales/de.yml b/config/locales/de.yml index b13656fe2..aa24782b4 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -198,4 +198,5 @@ de: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" - label_clock: clock in/out \ No newline at end of file + label_clock: clock in/out + label_hours: Hours \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index b0605239d..425bfeab9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -199,5 +199,6 @@ en: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" - label_clock: clock in/out + label_clock: Clock in/out + label_hours: Hours \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6018b6462..61c830758 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -199,4 +199,5 @@ fr: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" - label_clock: clock in/out \ No newline at end of file + label_clock: clock in/out + label_hours: Hours \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index 507d2271d..4c02ea995 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -196,4 +196,5 @@ it: error_expense_entry_delete: "Cannot be deleted. The expensesheet with this entry is locked" button_populate_leave: "Run Period End Process" text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" - label_clock: clock in/out \ No newline at end of file + label_clock: clock in/out + label_hours: Hours \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a91ccc088..e5732b3b6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,7 +32,8 @@ get 'wktime/testapi', :to => 'wktime#testapi' - get 'wktime/updateAttendance', :to => 'wktime#updateAttendance' + #get 'wktime/updateAttendance', :to => 'wktime#updateAttendance' +match 'updateAttendance', :controller => 'wktime', :action => 'updateAttendance', :via => [:get] get 'wktime/time_rpt', :to => 'wktime#time_rpt' @@ -98,7 +99,15 @@ get 'wkattendance/getProjectByIssue', :to => 'wkattendance#getProjectByIssue' - get 'wkattendance/clockindex', :to => 'wkattendance#clockindex' + get 'wkattendance/clockindex', :to => 'wkattendance#clockindex' + + post 'wkattendance/clockindex', :to => 'wkattendance#clockindex' + + match 'wkattendance/clockedit', :to => 'wkattendance#clockedit', :via => [:get, :post] + +get 'wkattendance/getGroupMembers', :to => 'wkattendance#getGroupMembers' + + get 'wkattendance/getMembersbyGroup', :to => 'wkattendance#getMembersbyGroup' #For Report get 'wkreport/index', :to => 'wkreport#index' From 2c8b0b412cd11a6c4d3097a9317262b83095c187 Mon Sep 17 00:00:00 2001 From: Karthick Date: Wed, 3 Aug 2016 11:35:53 +0530 Subject: [PATCH 06/37] Manual attendance import with with hard-coded setting --- app/controllers/wkattendance_controller.rb | 118 +++++++++++++++++++ app/controllers/wkbase_controller.rb | 71 +++++------ app/helpers/wktime_helper.rb | 9 +- app/views/wkattendance/_list.html.erb | 3 + app/views/wkattendance/show.html.erb | 26 ++++ app/views/wktime/_attendance_widget.html.erb | 9 +- app/views/wktime/testapi.html.erb | 2 +- config/locales/de.yml | 3 +- config/locales/en.yml | 2 +- config/locales/fr.yml | 3 +- config/locales/it.yml | 3 +- config/routes.rb | 4 +- 12 files changed, 209 insertions(+), 44 deletions(-) create mode 100644 app/views/wkattendance/show.html.erb diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index ddd2fda99..23301dfe5 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -6,6 +6,7 @@ class WkattendanceController < WkbaseController before_filter :require_login before_filter :check_perm_and_redirect, :only => [:edit, :update] +require 'csv' def index @status = params[:status] || 1 @@ -371,4 +372,121 @@ def formPaginationCondition end rangeStr end + + def importAttendance + lastAttnEntriesHash = Hash.new + @errorHash = Hash.new + @importCount = 0 + userCFHash = Hash.new + custom_fields = UserCustomField.order('name') + userIdCFHash = Hash.new + unless custom_fields.blank? + userCFHash = Hash[custom_fields.map { |cf| [cf.name, cf.id] }] + end + csv = read_file + lastAttnEntries = findLastAttnEntry(false) + lastAttnEntries.each do |entry| + lastAttnEntriesHash[entry.user_id] = entry + end + columnArr = ["Employee Id","start_time","end_time"] + csv.each_with_index do |row,index| + # rowValueHash - Have the data of the current row + rowValueHash = Hash.new + columnArr.each_with_index do |col,i| + case col when "user_id" + rowValueHash["user_id"] = row[i] + when "start_time","end_time" + if row_date(row[i]).is_a?(DateTime) || (row[i].blank? && col == "end_time") + rowValueHash[col] = row_date(row[i]) + else + #isValid = false + @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + end + when "hours" + rowValueHash[col] = row[i].to_f + else + if index < 1 + cfId = userCFHash[col] + userIdCFHash = getUserIdCFHash(cfId) + end + if userIdCFHash[row[i]].blank? + @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + else + rowValueHash["user_id"] = userIdCFHash[row[i]] + end + end + end + # Check the row has any invalid entries and skip that row from import + if @errorHash[index+1].blank? + @importCount = @importCount + 1 + userId = rowValueHash["user_id"] #row[0].to_i + endEntry = nil + startEntry = getFormatedTimeEntry(rowValueHash["start_time"]) + if !rowValueHash["end_time"].blank? && (rowValueHash["end_time"] != rowValueHash["start_time"]) + endEntry = getFormatedTimeEntry(rowValueHash["end_time"]) + end + + if (columnArr.include? "end_time") && (columnArr.include? "start_time") + #Get the imported records for particular user and start_time + importedEntry = WkAttendance.where(:user_id => userId, :start_time => startEntry) + if importedEntry[0].blank? + # There is no records for the given user on the given start_time + # Insert a new record to the database + lastAttnEntriesHash[userId] = addNewAttendance(startEntry,endEntry,userId) + else + # Update the record with end Entry + if importedEntry[0].end_time.blank? && !endEntry.blank? + lastAttnEntriesHash[userId] = saveAttendance(importedEntry[0], startEntry, endEntry, userId, true) + end + end + else + # Get the imported records for particular user and entry_time + # Skip the records which is already inserted by check importedEntry[0].blank? + importedEntry = WkAttendance.where("user_id = ? AND (start_time = ? OR end_time = ?)", userId, startEntry, startEntry) + if importedEntry[0].blank? + lastAttnEntriesHash[userId] = saveAttendance(lastAttnEntriesHash[userId], startEntry, endEntry, userId, false) + end + end + end + end + + render :action => 'show' + end + + def read_file + csv_text = File.read("E://Project/Internal/TimeAndAttendance/doc/attnEntries/attenEntriesEndHours.csv") + csv_options = {:headers => true} + csv_options[:encoding] = 'UTF-8' + separator = ';' + csv_options[:col_sep] = separator if separator.size == 1 + wrapper = '"' + csv_options[:quote_char] = wrapper if wrapper.size == 1 + csv = CSV.parse(csv_text, csv_options) + csv + end + + def show + end + + def getFormatedTimeEntry(entryDateTime) + entryDateTime = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) + entryTime = Time.parse("#{entryDateTime.utc.to_date.to_s} #{entryDateTime.utc.to_time.to_s} ").localtime + entryTime + end + + def getUserIdCFHash(cfId) + cfValHash = Hash.new + cfValue = CustomValue.where("custom_field_id = #{cfId}") + unless cfValue.blank? + #cfs = custom_fields.collect {|cf| userCFHash[cf.name] = cf.id } + cfValHash = Hash[cfValue.map { |cfv| [cfv.value, cfv.customized_id] }] + end + cfValHash + end + + def row_date(dateTimeStr) + format = "%m/%d/%y %T" + DateTime.strptime(dateTimeStr, format) rescue dateTimeStr + end + end diff --git a/app/controllers/wkbase_controller.rb b/app/controllers/wkbase_controller.rb index 88ea7d3f7..2ffee2a11 100644 --- a/app/controllers/wkbase_controller.rb +++ b/app/controllers/wkbase_controller.rb @@ -1,49 +1,54 @@ class WkbaseController < ApplicationController unloadable - - def updateClockInOut - if !findLastAttnEntry.blank? - @lastAttnEntry = findLastAttnEntry[0] + lastAttnEntries = findLastAttnEntry(true) + if !lastAttnEntries.blank? + @lastAttnEntry = lastAttnEntries[0] end currentDate = (DateTime.parse params[:startdate]) - if params[:str] != "start" #&& isAccountUser - entrydate = @lastAttnEntry.start_time - start_local = entrydate.localtime - if ((Date.parse params[:startdate]) != @lastAttnEntry.start_time.to_date) - endtime = start_local.change({ hour: "23:59".to_time.strftime("%H"), min: "23:59".to_time.strftime("%M"), sec: '59' }) - addNewAttendance - else - endtime = start_local.change({ hour: currentDate.to_time.strftime("%H"), min:currentDate.to_time.strftime("%M"), sec: currentDate.to_time.strftime("%S") }) - end - @lastAttnEntry.end_time = endtime - @lastAttnEntry.hours = computeWorkedHours(@lastAttnEntry.start_time,@lastAttnEntry.end_time, true) - @lastAttnEntry.save() - else - addNewAttendance - end + entryTime = Time.parse("#{currentDate.utc.to_date.to_s} #{currentDate.utc.to_time.to_s} ").localtime + @lastAttnEntry = saveAttendance(@lastAttnEntry, entryTime, nil, User.current.id, false) ret = 'done' respond_to do |format| format.text { render :text => ret } end end - def addNewAttendance + def addNewAttendance(startEntry,endEntry,userId) wkattendance = WkAttendance.new - currentDate = DateTime.parse params[:startdate] - entrydate = Date.parse params[:startdate] - wkattendance.user_id = params[:user_id].to_i - if params[:str] != "start" - wkattendance.start_time = Time.parse("#{entrydate.to_s} 00:00:00 ").localtime.to_s - wkattendance.end_time = currentDate - endtime = currentDate - wkattendance.hours = computeWorkedHours(wkattendance.start_time,wkattendance.end_time, true) + wkattendance.start_time = startEntry + wkattendance.end_time = endEntry + wkattendance.hours = computeWorkedHours(wkattendance.start_time,wkattendance.end_time, true) unless endEntry.blank? + wkattendance.user_id = userId + wkattendance.save() + wkattendance + end + + def saveAttendance(attnObj, startTime, endTime, userId, hasStartEnd) + wkattendance = nil + if(!attnObj.blank? && ((attnObj.end_time.blank? && attnObj.start_time > (startTime - 1.day) )|| hasStartEnd)) + if !hasStartEnd + entrydate = attnObj.start_time + start_local = entrydate.localtime + if ((startTime.to_date) != attnObj.start_time.to_date) + endtime = start_local.change({ hour: "23:59".to_time.strftime("%H"), min: "23:59".to_time.strftime("%M"), sec: '59' }) + nextDayStart = Time.parse("#{startTime.to_date.to_s} 00:00:00 ").localtime.to_s + wkattendance = addNewAttendance(nextDayStart,startTime,userId) + else + endtime = start_local.change({ hour: startTime.localtime.strftime("%H"), min:startTime.localtime.strftime("%M"), sec: startTime.localtime.strftime("%S") }) + end + else + endtime = endTime + end + + attnObj.end_time = endtime + attnObj.hours = computeWorkedHours(attnObj.start_time,attnObj.end_time, true) + attnObj.save() + wkattendance = attnObj if wkattendance.blank? else - wkattendance.start_time = currentDate - endtime = nil + wkattendance = addNewAttendance(startTime,endTime,userId) end - wkattendance.user_id = User.current.id - wkattendance.save() - end + wkattendance + end end diff --git a/app/helpers/wktime_helper.rb b/app/helpers/wktime_helper.rb index 7dd0848de..8ec610eb4 100644 --- a/app/helpers/wktime_helper.rb +++ b/app/helpers/wktime_helper.rb @@ -882,8 +882,13 @@ def getNonSubmissionUserIds userIds end - def findLastAttnEntry - WkAttendance.find_by_sql("select a.* from wk_attendances a inner join ( select max(start_time) as start_time,user_id from wk_attendances where user_id = #{User.current.id} group by user_id ) vw on a.start_time = vw.start_time and a.user_id = vw.user_id order by a.start_time ") + def findLastAttnEntry(isCurrentUser) + if isCurrentUser + lastAttnEntries = WkAttendance.find_by_sql("select a.* from wk_attendances a inner join ( select max(start_time) as start_time,user_id from wk_attendances where user_id = #{User.current.id} group by user_id ) vw on a.start_time = vw.start_time and a.user_id = vw.user_id order by a.start_time ") + else + lastAttnEntries = WkAttendance.find_by_sql("select a.* from wk_attendances a inner join ( select max(start_time) as start_time,user_id from wk_attendances group by user_id ) vw on a.start_time = vw.start_time and a.user_id = vw.user_id order by a.start_time ") + end + lastAttnEntries end def computeWorkedHours(startTime,endTime, ishours) diff --git a/app/views/wkattendance/_list.html.erb b/app/views/wkattendance/_list.html.erb index f2aab12d3..eb0ad2788 100644 --- a/app/views/wkattendance/_list.html.erb +++ b/app/views/wkattendance/_list.html.erb @@ -6,6 +6,9 @@
<%= link_to l(:"button_populate_leave"), url_for(:controller => controller_name, :action => 'runPeriodEndProcess', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%>
+
+<%= link_to l(:"label_import_attendance"), url_for(:controller => controller_name, :action => 'importAttendance', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%> +
<%= form_tag({:controller => controller_name, :action => 'index'}, :method => :get) do %>
<%= l(:label_filter_plural) %> diff --git a/app/views/wkattendance/show.html.erb b/app/views/wkattendance/show.html.erb new file mode 100644 index 000000000..6434cd7f9 --- /dev/null +++ b/app/views/wkattendance/show.html.erb @@ -0,0 +1,26 @@ +

<%= l(:label_import_attendance) %>

+ +<% if @importCount > 0 %> +

<%= l(:notice_import_finished, :count => @importCount) %>:

+<% end %> + +<% if !@errorHash.blank? && @errorHash.count > 0 %> +

<%= l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount)) %>:

+ + + + + + + + + + <% @errorHash.each do |item| %> + + + + + <% end %> + +
PositionMessage
<%= item[0] %><%= simple_format_without_paragraph item[1] %>
+<% end %> \ No newline at end of file diff --git a/app/views/wktime/_attendance_widget.html.erb b/app/views/wktime/_attendance_widget.html.erb index 0b6cdd94b..e079fc33f 100644 --- a/app/views/wktime/_attendance_widget.html.erb +++ b/app/views/wktime/_attendance_widget.html.erb @@ -1,7 +1,10 @@ <% wktime_helper = Object.new.extend(WktimeHelper) %> -<% if !wktime_helper.findLastAttnEntry.blank? - @lastAttnEntry = wktime_helper.findLastAttnEntry[0] - end %> +<% + lastAttnEntries = wktime_helper.findLastAttnEntry(true) + if !lastAttnEntries.blank? + @lastAttnEntry = lastAttnEntries[0] + end +%> <% if (!Setting.plugin_redmine_wktime['wktime_enable_clock_in_out'].blank? && Setting.plugin_redmine_wktime['wktime_enable_clock_in_out'].to_i == 1) && (!Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].blank? && Setting.plugin_redmine_wktime['wktime_enable_attendance_module'].to_i == 1 ) %> <% if !@lastAttnEntry.blank? diff --git a/app/views/wktime/testapi.html.erb b/app/views/wktime/testapi.html.erb index 46e96a1ca..625e94a8e 100644 --- a/app/views/wktime/testapi.html.erb +++ b/app/views/wktime/testapi.html.erb @@ -1,6 +1,6 @@ Time & Expense -
+
<%= l(:label_wk_attendance) %> -

+

<%= check_box_tag('settings[wktime_enable_attendance_module]', 1, @settings['wktime_enable_attendance_module'].to_i == 1) %>

-

+

<%= check_box_tag('settings[wktime_enable_clock_in_out]', 1, @settings['wktime_enable_clock_in_out'].to_i == 1) %>

-

+

<%= check_box_tag('settings[wktime_work_time_header]', 1, @settings['wktime_work_time_header'].to_i == 1) %>

-

+

<% breakTime = [] if(@settings['wktime_break_time'].blank?) @@ -44,7 +44,7 @@ lblYear = "<%=l(:label_year) %>"; options_for_select(breakTime, :selected => 'settings[wktime_break_time]'), :multiple=> true, :style => "width:200px; height:100px;")%>

-

+

<%= link_to "Add", "javascript:showBreakTimeDialog('Add');", :class => "button"%> | <%= link_to "Edit", "javascript:showBreakTimeDialog('Edit');", :class => "button"%> | <%= link_to "Delete", "javascript:removeSelectedValue('settings_wktime_break_time');", :class => "button" %> @@ -90,7 +90,7 @@ lblYear = "<%=l(:label_year) %>";

<%= l(:label_hours_note) %>

-

+

<% leave = [] issue_list = Issue.order('subject') @@ -124,7 +124,7 @@ lblYear = "<%=l(:label_year) %>"; options_for_select(leave, :selected => 'settings[wktime_leave]'), :multiple=> true, :style => "min-width:200px; height:100px;")%>

-

+

<%= link_to "Add", "javascript:showLeaveDialog('Add');", :class => "button"%> | <%= link_to "Edit", "javascript:showLeaveDialog('Edit');", :class => "button"%> | <%= link_to "Delete", "javascript:removeSelectedValue('settings_wktime_leave');", :class => "button" %> @@ -163,8 +163,12 @@ lblYear = "<%=l(:label_year) %>"; <% custom_fields = UserCustomField.order('name') - unless custom_fields.blank? - cfdate = custom_fields.select {|cf| cf.field_format == 'date' } + allFields = Hash.new() + fldInFiles = Hash.new() + allFields = {"user_id" => "#{l(:label_user_id)}", "start_time" => "#{l(:label_start_time)}", "end_time" => "#{l(:label_end_time)}", "hours" => "#{l(:label_hours)}" } + unless custom_fields.blank? + cfdate = custom_fields.select {|cf| cf.field_format == 'date'} + cfids = custom_fields.select {|cf| cf.field_format == 'string' || cf.field_format == 'int' } unless cfdate.blank? cfd = cfdate.collect {|cf| [cf.name, cf.id] } cfd.unshift(["",0]) @@ -172,38 +176,123 @@ lblYear = "<%=l(:label_year) %>"; cfd = Array.new cfd << [ "", 0] end + + unless cfids.blank? + cfids.collect {|cf| + allFields.store("#{cf.id}", cf.name)} + end + cfs = custom_fields.collect {|cf| [cf.name, cf.id] } cfs.unshift(["",0]) else cfd = Array.new - cfd << [ "", 0] + cfd << [ "", 0] cfs = Array.new cfs << [ "", 0] end + available_fields = allFields + selectedfld = Setting.plugin_redmine_wktime['wktime_fields_in_file'] + if !selectedfld.blank? + fldInFiles = allFields.select {|key,value| selectedfld.include? key.to_s} + available_fields = allFields.select {|key,value| !selectedfld.include? key.to_s} + end %> -

+

<%=h select_tag('settings[wktime_attn_join_date_cf]', options_for_select(cfd, :selected => @settings['wktime_attn_join_date_cf'])) %>

-

+

<%=h select_tag('settings[wktime_attn_terminate_date_cf]', options_for_select(cfd, :selected => @settings['wktime_attn_terminate_date_cf'])) %>

-

+

<%=h select_tag('settings[wktime_attn_user_dob_cf]', options_for_select(cfd, :selected => @settings['wktime_attn_user_dob_cf'])) %>

-

+

<%=h select_tag('settings[wktime_attn_designation_cf]', options_for_select(cfs, :selected => @settings['wktime_attn_designation_cf'])) %>

-

+

<%=h select_tag('settings[wktime_attn_employee_id_cf]', options_for_select(cfs, :selected => @settings['wktime_attn_employee_id_cf'])) %>

+
+ <%= l(:button_import) %> +

+ <%= check_box_tag('settings[wktime_auto_import]', 1, @settings['wktime_auto_import'].to_i == 1) %> +

+

+ + <%= select_tag 'settings[wktime_field_separator]', + options_for_select([[l(:label_comma_char), ','], [l(:label_semi_colon_char), ';']], :selected => @settings['wktime_field_separator'].blank? ? 0 : @settings['wktime_field_separator']) %> +

+

+ + <%= select_tag 'settings[wktime_field_wrapper]', + options_for_select([[l(:label_quote_char), "'"], [l(:label_double_quote_char), '"']], :selected => @settings['wktime_field_wrapper'].blank? ? 0 : @settings['wktime_field_wrapper']) %> +

+

+ + <%= select_tag 'settings[wktime_field_encoding]', options_for_select(Setting::ENCODINGS, :selected => @settings['wktime_field_encoding'].blank? ? 0 : @settings['wktime_field_encoding']) %> +

+

+ + <% wktime_helper = Object.new.extend(WktimeHelper) %> + <%= select_tag 'settings[wktime_field_datetime]', options_for_select(wktime_helper.date_format_options, :selected => @settings['wktime_field_datetime'].blank? ? 0 : @settings['wktime_field_datetime'] ) %> +

+ + + + + + + + + + + + + + + + + +

    + <%= select_tag('settings[wktime_avialable_fields]', options_for_select(available_fields.invert, :selected => @settings['wktime_avialable_fields'] ), :multiple => true, :size=> 10, :style => "min-width:100px; ") %> + + +
+ +
+ <%= select_tag('settings[wktime_fields_in_file]', options_for_select(fldInFiles.invert, :selected => @settings['wktime_fields_in_file'] ), multiple: true, size: 10, :style => "min-width:100px; ") %> +
+

+ + <% + hr = [] + for i in 0..23 + if i < 10 + hr << ['0' + i.to_s,i] + else + hr << [i,i] + end + end + %> + <%= l(:field_hours) %> <%= select_tag('settings[wktime_auto_import_time_hr]', options_for_select(hr, + :selected => @settings['wktime_auto_import_time_hr'].blank? ? 23 : @settings['wktime_auto_import_time_hr']))%> + <%= l(:label_wk_minutes) %> <%= select_tag('settings[wktime_auto_import_time_min]', options_for_select([['00',0], + [15, 15], + [30, 30], + [45, 45]], :selected => @settings['wktime_auto_import_time_min'].blank? ? 0 : @settings['wktime_auto_import_time_min']))%> +

+

+ <%= text_field_tag 'settings[wktime_file_to_import]', @settings['wktime_file_to_import'], :size => 50 %> +

+
<% if !projArr.blank? %>
<%=h select_tag('template_projDD', options_for_select(projArr))%> diff --git a/assets/javascripts/settings.js b/assets/javascripts/settings.js index 40e2ce816..6287141c7 100644 --- a/assets/javascripts/settings.js +++ b/assets/javascripts/settings.js @@ -346,6 +346,14 @@ function updateCustFldDD(currCFDD,anotherCFDD) lvlistbox.options[i].selected = true; } } + var fldInFiles=document.getElementById("settings_wktime_fields_in_file"); + if(fldInFiles != null) + { + for(i = 0; i < fldInFiles.options.length; i++) + { + fldInFiles.options[i].selected = true; + } + } }); function validateDate(date) @@ -478,3 +486,28 @@ function updateCustFldDD(currCFDD,anotherCFDD) } } + +function listbox_moveacross(sourceID, destID) { + var src = document.getElementById(sourceID); + var dest = document.getElementById(destID); + + for(var count=0; count < src.options.length; count++) { + + if(src.options[count].selected == true) { + var option = src.options[count]; + + var newOption = document.createElement("option"); + newOption.value = option.value; + newOption.text = option.text; + newOption.selected = true; + try { + dest.add(newOption, null); //Standard + src.remove(count, null); + }catch(error) { + dest.add(newOption); // IE only + src.remove(count); + } + count--; + } + } +} \ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml index 56d64e2d4..1bd9b96fa 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -200,4 +200,12 @@ de: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance \ No newline at end of file + label_import_attendance: Import attendance + label_path: Import file path + label_auto_import: Auto Import + label_auto_import_time: Auto Import Every + label_start_time: Starttime + label_end_time: Endtime + label_user_id: Userid + label_available_fields: Available Fields + label_fields_in_file: Fields in File \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index eed755d29..08a164b0f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -201,4 +201,12 @@ en: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: Clock in/out label_hours: Hours - label_import_attendance: Import attendance \ No newline at end of file + label_import_attendance: Import attendance + label_path: Import file path + label_auto_import: Auto Import + label_auto_import_time: Auto Import Every + label_start_time: Starttime + label_end_time: Endtime + label_user_id: Userid + label_available_fields: Available Fields + label_fields_in_file: Fields in File \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index d05a46de2..38f9c36fc 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -201,4 +201,12 @@ fr: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance \ No newline at end of file + label_import_attendance: Import attendance + label_path: Import file path + label_auto_import: Auto Import + label_auto_import_time: Auto Import Every + label_start_time: Starttime + label_end_time: Endtime + label_user_id: Userid + label_available_fields: Available Fields + label_fields_in_file: Fields in File \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index 979545622..2b6b429b0 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -198,4 +198,12 @@ it: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance \ No newline at end of file + label_import_attendance: Import attendance + label_path: Import file path + label_auto_import: Auto Import + label_auto_import_time: Auto Import Every + label_start_time: Starttime + label_end_time: Endtime + label_user_id: Userid + label_available_fields: Available Fields + label_fields_in_file: Fields in File \ No newline at end of file diff --git a/init.rb b/init.rb index d01676525..79e3b363c 100644 --- a/init.rb +++ b/init.rb @@ -231,7 +231,17 @@ def destroy 'wktime_min_hour_week' => '0', 'wktime_enable_expense_module' => '1', 'wktime_enable_report_module' => '1', - 'wktime_enable_attendance_module' => '1' + 'wktime_enable_attendance_module' => '1', + 'wktime_auto_import' => '0', + 'wktime_field_separator' => ['0'], + 'wktime_field_wrapper' => ['0'], + 'wktime_field_encoding' => ['0'], + 'wktime_field_datetime' => ['0'], + 'wktime_avialable_fields' => ['0'], + 'wktime_fields_in_file' => ['0'], + 'wktime_auto_import_time_hr' => '23', + 'wktime_auto_import_time_min' => '0', + 'wktime_file_to_import' => '0' }) menu :top_menu, :wkTime, { :controller => 'wktime', :action => 'index' }, :caption => :label_ta, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission } From 5d8ab4fe801137db7ffe8df28c3b300d1e2af97b Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Fri, 5 Aug 2016 18:43:26 +0530 Subject: [PATCH 12/37] Fill Total hours row in attendance report --- app/views/wkreport/reportattn.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/wkreport/reportattn.html.erb b/app/views/wkreport/reportattn.html.erb index 861268483..b318de979 100644 --- a/app/views/wkreport/reportattn.html.erb +++ b/app/views/wkreport/reportattn.html.erb @@ -104,15 +104,17 @@ <%=h (accrual1.blank? && used1.blank? ? '' : (balance1.blank? ? 0 : balance1) + (accrual1.blank? ? 0 : accrual1) - (used1.blank? ? 0 : used1)) %> <%=h (accrual2.blank? && used2.blank? ? '' : (balance2.blank? ? 0 : balance2) + (accrual2.blank? ? 0 : accrual2) - (used2.blank? ? 0 : used2)) %> <%=h (accrual3.blank? && used3.blank? ? '' : (balance3.blank? ? 0 : balance3) + (accrual3.blank? ? 0 : accrual3) - (used3.blank? ? 0 : used3)) %> +<% totalhours = 0%> <% for i in 1..31 hour = @attendance_entries[entry.id.to_s + '_' + i.to_s + '_hours'] leave = @attendance_entries[entry.id.to_s + '_' + i.to_s + '_leave'] attn_entry = shortName[leave].blank? ? hour : (hour.blank? ? shortName[leave] : (hour.to_s) + "/ " + shortName[leave]) + totalhours += hour.blank? ? 0 : hour %> <%=h attn_entry %> <% end -%> <%=h "" %> -<%=h "" %> +<%=h totalhours.to_s %> <%=h "" %> <%if showSlno %> <%=h index+1 %> From fd7a4b9a6a97a84c104f3dc14a5809addb483c14 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Mon, 8 Aug 2016 11:39:07 +0530 Subject: [PATCH 13/37] add file headers setting in attendances setting --- app/views/settings/_tab_attendance.html.erb | 3 +++ config/locales/de.yml | 3 ++- config/locales/en.yml | 3 ++- config/locales/fr.yml | 3 ++- config/locales/it.yml | 3 ++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/views/settings/_tab_attendance.html.erb b/app/views/settings/_tab_attendance.html.erb index f02887a07..912391a09 100644 --- a/app/views/settings/_tab_attendance.html.erb +++ b/app/views/settings/_tab_attendance.html.erb @@ -224,6 +224,9 @@ lblYear = "<%=l(:label_year) %>";

<%= check_box_tag('settings[wktime_auto_import]', 1, @settings['wktime_auto_import'].to_i == 1) %>

+

+ <%= check_box_tag('settings[wktime_import_file_headers]', 1, @settings['wktime_import_file_headers'].to_i == 1) %> +

<%= select_tag 'settings[wktime_field_separator]', diff --git a/config/locales/de.yml b/config/locales/de.yml index 1bd9b96fa..39fc70417 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -208,4 +208,5 @@ de: label_end_time: Endtime label_user_id: Userid label_available_fields: Available Fields - label_fields_in_file: Fields in File \ No newline at end of file + label_fields_in_file: Fields in File + label_import_file_headers: File Headers \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 08a164b0f..dcbc20be2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -209,4 +209,5 @@ en: label_end_time: Endtime label_user_id: Userid label_available_fields: Available Fields - label_fields_in_file: Fields in File \ No newline at end of file + label_fields_in_file: Fields in File + label_import_file_headers: File Headers \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 38f9c36fc..5478463d5 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -209,4 +209,5 @@ fr: label_end_time: Endtime label_user_id: Userid label_available_fields: Available Fields - label_fields_in_file: Fields in File \ No newline at end of file + label_fields_in_file: Fields in File + label_import_file_headers: File Headers \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index 2b6b429b0..d142e496f 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -206,4 +206,5 @@ it: label_end_time: Endtime label_user_id: Userid label_available_fields: Available Fields - label_fields_in_file: Fields in File \ No newline at end of file + label_fields_in_file: Fields in File + label_import_file_headers: File Headers \ No newline at end of file From 3829a4eec3c2d6c744a10c49b6fee5612e93d261 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Mon, 8 Aug 2016 11:49:55 +0530 Subject: [PATCH 14/37] comments worktime header clock in/out methods --- app/views/wktime/_worktime_header.html.erb | 19 +++++-------------- assets/javascripts/edit.js | 14 +++++++------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/app/views/wktime/_worktime_header.html.erb b/app/views/wktime/_worktime_header.html.erb index 8f0d1df00..b60bc8b35 100644 --- a/app/views/wktime/_worktime_header.html.erb +++ b/app/views/wktime/_worktime_header.html.erb @@ -42,21 +42,12 @@ <% if (isEditable) %>

-
- <%=h text_field_tag( "#{str}_#{(i+1)}" , "#{str}" == "start" ? ($headerStartTime[i+1].blank? ? '00:00' : $headerStartTime[i+1].first(1)) : ($headerEndTime[i+1].blank? ? '00:00' : $headerEndTime[i+1].last(1)),:size => 4, :disabled => true, :class => (@startday + i) < Date.today ? 'clock-textbox' : ((@startday + i) == Date.today ? 'clock-todaytextbox' : '' ), :onchange => "validateHr(this,#{(i+1)});") %> - <%=h hidden_field_tag('hd' + "#{str}_#{(i+1)}", !nightclkout ? ( $headerEntriesId[i+1].blank? ? '' : $headerEntriesId[i+1].last(1)) : ( $headerEntriesId[i].blank? ? '' : $headerEntriesId[i].last(1)) ) %> - <%=h hidden_field_tag('hours' + "#{str}_#{(i+1)}", ( $headerhoursdiff[i+1].blank? ? '' : $headerhoursdiff[i+1].last(1)) ) %> -
- - <% if ("#{str}" == "start" || "#{str}" == "end") && controller.showWorktimeHeader && (i == col_num) && User.current.id == @user.id %> - <% imgname = "#{str}" == "start" ? "clockin.jpg" : "clockout.jpg" %> -
- <% image_tg = image_tag("#{imgname}", :id => "#{str}" == "start" ? 'start_img' : 'end_img' , :plugin => "redmine_wktime", :title => "#{str}" == "start" ? l(:label_clock_in) : l(:label_clock_out), :style => "display:none;") %> - <%= link_to image_tg, "javascript:setClockInOut('#{str}','#{!nightclkout ? col_num : col_num-1}');", {:id => "clock_#{str}"} %> -
+
+ <%=h text_field_tag( "#{str}_#{(i+1)}" , "#{str}" == "start" ? ($headerStartTime[i+1].blank? ? '00:00' : $headerStartTime[i+1].first(1)) : ($headerEndTime[i+1].blank? ? '00:00' : $headerEndTime[i+1].last(1)),:size => 4, :disabled => true, :class => (@startday + i) < Date.today ? 'clock-textbox' : ((@startday + i) == Date.today ? 'clock-todaytextbox' : '' ), :onchange => "validateHr(this,#{(i+1)});") %> + <%=h hidden_field_tag('hd' + "#{str}_#{(i+1)}", !nightclkout ? ( $headerEntriesId[i+1].blank? ? '' : $headerEntriesId[i+1].last(1)) : ( $headerEntriesId[i].blank? ? '' : $headerEntriesId[i].last(1)) ) %> + <%=h hidden_field_tag('hours' + "#{str}_#{(i+1)}", ( $headerhoursdiff[i+1].blank? ? '' : $headerhoursdiff[i+1].last(1)) ) %> +
- <% end %> -
<% else %> diff --git a/assets/javascripts/edit.js b/assets/javascripts/edit.js index df43d1dda..9cb8f436b 100644 --- a/assets/javascripts/edit.js +++ b/assets/javascripts/edit.js @@ -1395,7 +1395,7 @@ function showclkDialog(day) } } } - +/* function setClockInOut(strid,id) { if(nscount > 0) { @@ -1495,7 +1495,7 @@ function hiddenClockInOut(data,strid,id){ nscount = 1; } } - +*/ function timeFormat(minutes) { var tot_Hr1 = 0,tot_min1 = 0,totTime1 =""; @@ -1511,7 +1511,7 @@ function timeFormat(minutes) }; return totTime1; } - +/* function calculatebreakTime(totTime, day, element) { @@ -1628,7 +1628,7 @@ function calculatebreakTime(totTime, day, element) } } - +*/ function MinutesDifferent(totTime, stdiff, variation) { var minutessdiff; // minusdiff @@ -1653,7 +1653,7 @@ function MinutesDifferent(totTime, stdiff, variation) minutessdiff = ((h > 0 ? h + ":" + (m < 10 ? "0" : "") : "") + (h > 0 ? m : ("0:" + m)) ); return minutessdiff; } - +/* function dateCompare(time1,time2,s) { var t1 = new Date(); var parts = time1.split(":"); @@ -1684,7 +1684,7 @@ function dateCompare(time1,time2,s) { } return 0; } - +*/ function timeStringToFloat(time) { var hoursMinutes = time.split(/[.:]/); var hours = parseInt(hoursMinutes[0], 10); @@ -1708,7 +1708,7 @@ function updateAtt(param, diff,str,id) url: '/updateAttendance', type: 'get', data: {editvalue : param, startdate : datevalue, user_id : userid, nightshift : nightshift, isdate : date}, - success: function(data){ if(!diff){ hiddenClockInOut(data, str, id);}else{ newClockInOut(data); } }, + success: function(data){ if(diff){ newClockInOut(data); } }, }); } From 03a855c62a992250a6fdf871be831cead95e6aad Mon Sep 17 00:00:00 2001 From: Karthick Date: Mon, 8 Aug 2016 19:33:36 +0530 Subject: [PATCH 15/37] Copmlete attendance import --- app/controllers/wkattendance_controller.rb | 11 ++++- app/helpers/wkattendance_helper.rb | 53 +++++++++++++++------ app/views/settings/_tab_attendance.html.erb | 6 ++- app/views/wkattendance/_list.html.erb | 2 +- app/views/wkattendance/new.html.erb | 11 +++++ app/views/wkattendance/show.html.erb | 45 ++++++++--------- config/routes.rb | 7 ++- init.rb | 32 ++++++++++++- 8 files changed, 124 insertions(+), 43 deletions(-) create mode 100644 app/views/wkattendance/new.html.erb diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 90ea3e29d..2d403871d 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -371,14 +371,21 @@ def formPaginationCondition rangeStr = " LIMIT " + @limit.to_s + " OFFSET " + @offset.to_s end rangeStr - end + end + + def new + end def show + file = params[:file] + filePath = file.path begin - importAttendance + isSuccess = importAttendance(filePath, false) + #redirect_to :action => 'show' rescue Exception => e @errorMsg = "Import failed: #{e.message}" flash[:error] = @errorMsg + redirect_to :action => 'new' end end diff --git a/app/helpers/wkattendance_helper.rb b/app/helpers/wkattendance_helper.rb index bb37aeedf..ad1145532 100644 --- a/app/helpers/wkattendance_helper.rb +++ b/app/helpers/wkattendance_helper.rb @@ -1,6 +1,6 @@ module WkattendanceHelper include WktimeHelper - + require 'csv' #Copied from UserHelper def users_status_options_for_select(selected) user_count_by_status = User.group('status').count.to_hash @@ -125,7 +125,7 @@ def deleteWkUserLeaves(userId, accrualOn) end end - def importAttendance + def importAttendance(file,isAuto) lastAttnEntriesHash = Hash.new @errorHash = Hash.new @importCount = 0 @@ -133,14 +133,14 @@ def importAttendance custom_fields = UserCustomField.order('name') userIdCFHash = Hash.new unless custom_fields.blank? - userCFHash = Hash[custom_fields.map { |cf| [cf.name, cf.id] }] + userCFHash = Hash[custom_fields.map { |cf| [cf.id, cf.name] }] end - csv = read_file + csv = read_file(file) lastAttnEntries = findLastAttnEntry(false) lastAttnEntries.each do |entry| lastAttnEntriesHash[entry.user_id] = entry end - columnArr = ["Employee Id","start_time","end_time"] + columnArr = Setting.plugin_redmine_wktime['wktime_fields_in_file'] csv.each_with_index do |row,index| # rowValueHash - Have the data of the current row rowValueHash = Hash.new @@ -158,11 +158,11 @@ def importAttendance rowValueHash[col] = row[i].to_f else if index < 1 - cfId = userCFHash[col] + cfId = col.to_i #userCFHash[col] userIdCFHash = getUserIdCFHash(cfId) end if userIdCFHash[row[i]].blank? - @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + @errorHash[index+1] = userCFHash[col.to_i] + " " + l('activerecord.errors.messages.invalid') else rowValueHash["user_id"] = userIdCFHash[row[i]] end @@ -201,15 +201,34 @@ def importAttendance end end end + if isAuto + Rails.logger.info("====== File Name = #{File.basename file}=========") + if @importCount > 0 + Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") + end + if !@errorHash.blank? && @errorHash.count > 0 + Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") + Rails.logger.info("===============================================================") + Rails.logger.info(" Row || Message ") + Rails.logger.info("===============================================================") + @errorHash.each do |item| + Rails.logger.info(" #{item[0]} || #{simple_format_without_paragraph item[1]}") + Rails.logger.info("---------------------------------------------------------------") + end + Rails.logger.info("===============================================================") + end + end + return @errorHash.blank? || @errorHash.count < 0 end - def read_file - csv_text = File.read("E://Project/Internal/TimeAndAttendance/doc/attnEntries/attenEntriesEndHours.csv") - csv_options = {:headers => true} - csv_options[:encoding] = 'UTF-8' - separator = ';' + def read_file(file) + csv_text = File.read(file) + hasHeaders = (Setting.plugin_redmine_wktime['wktime_import_file_headers'].blank? || Setting.plugin_redmine_wktime['wktime_import_file_headers'].to_i == 0) ? false : true + csv_options = {:headers => hasHeaders} + csv_options[:encoding] = Setting.plugin_redmine_wktime['wktime_field_encoding']#'UTF-8' + separator = Setting.plugin_redmine_wktime['wktime_field_separator']#',' csv_options[:col_sep] = separator if separator.size == 1 - wrapper = '"' + wrapper = Setting.plugin_redmine_wktime['wktime_field_wrapper']#'"' csv_options[:quote_char] = wrapper if wrapper.size == 1 csv = CSV.parse(csv_text, csv_options) csv @@ -232,7 +251,7 @@ def getUserIdCFHash(cfId) end def row_date(dateTimeStr) - format = "%m/%d/%y %T" + format = Setting.plugin_redmine_wktime['wktime_field_datetime']#"%Y-%m-%d %T" DateTime.strptime(dateTimeStr, format) rescue dateTimeStr end @@ -272,5 +291,11 @@ def saveAttendance(attnObj, startTime, endTime, userId, hasStartEnd) end wkattendance end + + def calcSchdulerInterval + interval = (Setting.plugin_redmine_wktime['wktime_auto_import_time_hr'].to_i*60) + (Setting.plugin_redmine_wktime['wktime_auto_import_time_min'].to_i) + intervalMin = interval>0 ? interval.to_s + 'm' : '60m' + intervalMin + end end diff --git a/app/views/settings/_tab_attendance.html.erb b/app/views/settings/_tab_attendance.html.erb index 912391a09..ee25e86e2 100644 --- a/app/views/settings/_tab_attendance.html.erb +++ b/app/views/settings/_tab_attendance.html.erb @@ -193,7 +193,9 @@ lblYear = "<%=l(:label_year) %>"; available_fields = allFields selectedfld = Setting.plugin_redmine_wktime['wktime_fields_in_file'] if !selectedfld.blank? - fldInFiles = allFields.select {|key,value| selectedfld.include? key.to_s} + selectedfld.each do |field| + fldInFiles[field] = allFields[field] + end available_fields = allFields.select {|key,value| !selectedfld.include? key.to_s} end %> @@ -259,7 +261,7 @@ lblYear = "<%=l(:label_year) %>";     - <%= select_tag('settings[wktime_avialable_fields]', options_for_select(available_fields.invert, :selected => @settings['wktime_avialable_fields'] ), :multiple => true, :size=> 10, :style => "min-width:100px; ") %> + <%= select_tag('settings[wktime_avialable_fields]', options_for_select(available_fields.invert), :multiple => true, :size=> 10, :style => "min-width:100px; ") %> diff --git a/app/views/wkattendance/_list.html.erb b/app/views/wkattendance/_list.html.erb index a74b701cc..70b00ec76 100644 --- a/app/views/wkattendance/_list.html.erb +++ b/app/views/wkattendance/_list.html.erb @@ -7,7 +7,7 @@ <%= link_to l(:"button_populate_leave"), url_for(:controller => controller_name, :action => 'runPeriodEndProcess', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%>
-<%= link_to l(:"label_import_attendance"), url_for(:controller => controller_name, :action => 'show', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%> +<%= link_to l(:"label_import_attendance"), url_for(:controller => controller_name, :action => 'new', :tab => controller.controller_name)%>
<%= form_tag({:controller => controller_name, :action => 'index'}, :method => :get) do %>
<%= l(:label_filter_plural) %> diff --git a/app/views/wkattendance/new.html.erb b/app/views/wkattendance/new.html.erb new file mode 100644 index 000000000..ef7da8ef9 --- /dev/null +++ b/app/views/wkattendance/new.html.erb @@ -0,0 +1,11 @@ +

<%= l(:label_import_attendance) %>

+ +<%= form_tag wk_attendances_path, multipart: true do %> +
+ <%= l(:label_select_file_to_import) %> (CSV) +

+ <%= file_field_tag 'file' %> +

+
+

<%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %>

+<% end %> diff --git a/app/views/wkattendance/show.html.erb b/app/views/wkattendance/show.html.erb index 6434cd7f9..9a1f3591b 100644 --- a/app/views/wkattendance/show.html.erb +++ b/app/views/wkattendance/show.html.erb @@ -1,26 +1,27 @@

<%= l(:label_import_attendance) %>

+<% if @errorMsg.blank? %> + <% if @importCount > 0 %> +

<%= l(:notice_import_finished, :count => @importCount) %>

+ <% end %> -<% if @importCount > 0 %> -

<%= l(:notice_import_finished, :count => @importCount) %>:

-<% end %> + <% if !@errorHash.blank? && @errorHash.count > 0 %> +

<%= l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount)) %>

-<% if !@errorHash.blank? && @errorHash.count > 0 %> -

<%= l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount)) %>:

- - - - - - - - - - <% @errorHash.each do |item| %> - - - - - <% end %> - -
PositionMessage
<%= item[0] %><%= simple_format_without_paragraph item[1] %>
+ + + + + + + + + <% @errorHash.each do |item| %> + + + + + <% end %> + +
RowMessage
<%= item[0] %><%= simple_format_without_paragraph item[1] %>
+ <% end %> <% end %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a5f653735..ceb83b249 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -87,6 +87,9 @@ end #For Attendance + resources :wk_attendances, :controller => 'wkattendance' do + collection { post :show } + end get 'wkattendance/index', :to => 'wkattendance#index' post 'wkattendance/index', :to => 'wkattendance#index' @@ -122,5 +125,7 @@ get 'wkattendance/runPeriodEndProcess', :to => 'wkattendance#runPeriodEndProcess' - get 'wkattendance/show', :to => 'wkattendance#show' + post 'wkattendance/manualImport', :to => 'wkattendance#manualImport' + + get 'wkattendance/new', :to => 'wkattendance#new' \ No newline at end of file diff --git a/init.rb b/init.rb index 79e3b363c..7842e22b3 100644 --- a/init.rb +++ b/init.rb @@ -3,6 +3,7 @@ require 'wkpatch' require 'report_params' require_dependency '../lib/redmine/menu_manager' +require 'fileutils' # redmine only differs between project_menu and application_menu! but we want to display the @@ -241,7 +242,8 @@ def destroy 'wktime_fields_in_file' => ['0'], 'wktime_auto_import_time_hr' => '23', 'wktime_auto_import_time_min' => '0', - 'wktime_file_to_import' => '0' + 'wktime_file_to_import' => '0', + 'wktime_import_file_headers' => '0' }) menu :top_menu, :wkTime, { :controller => 'wktime', :action => 'index' }, :caption => :label_ta, :if => Proc.new { Object.new.extend(WktimeHelper).checkViewPermission } @@ -301,6 +303,34 @@ def destroy end end end + if (!Setting.plugin_redmine_wktime['wktime_auto_import'].blank? && Setting.plugin_redmine_wktime['wktime_auto_import'].to_i == 1) + require 'rufus/scheduler' + importScheduler = Rufus::Scheduler.new + wkattn_helper = Object.new.extend(WkattendanceHelper) + intervalMin = wkattn_helper.calcSchdulerInterval + #Scheduler will run at every intervalMin + importScheduler.every intervalMin do + begin + Rails.logger.info "==========Import Attendance - Started==========" + filePath = Setting.plugin_redmine_wktime['wktime_file_to_import'] + # Sort the files by modified date ascending order + sortedFilesArr = Dir.entries(filePath).sort_by { |x| File.mtime(filePath + "/" + x) } + sortedFilesArr.each do |filename| + next if File.directory? filePath + "/" + filename + isSuccess = wkattn_helper.importAttendance(filePath + "/" + filename, true ) + if !Dir.exists?("Processed") + FileUtils::mkdir_p filePath+'/Processed'#Dir.mkdir("Processed") + end + if isSuccess + FileUtils.mv filePath + "/" + filename, filePath+'/Processed', :force => true + Rails.logger.info("====== #{filename} moved processed directory=========") + end + end + rescue Exception => e + Rails.logger.info "Import failed: #{e.message}" + end + end + end end end From 1f886b573c91cc22bde1a6572866738a13e38e71 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Tue, 9 Aug 2016 12:23:26 +0530 Subject: [PATCH 16/37] sqlite3 issue: no time-sheets listed in view #54 --- app/controllers/wktime_controller.rb | 2 +- app/helpers/wktime_helper.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/wktime_controller.rb b/app/controllers/wktime_controller.rb index 5a7bf2724..1373676f2 100644 --- a/app/controllers/wktime_controller.rb +++ b/app/controllers/wktime_controller.rb @@ -1763,7 +1763,7 @@ def getQuery(teQuery, ids, from, to, status) dtRangeForUsrSqlStr = "(" + getAllWeekSql(from, to) + ") tmp1" teSqlStr = "(" + teQuery + ") tmp2" - query = "select tmp3.user_id, tmp3.spent_on, tmp3.#{spField}, tmp3.status, tmp3.status_updater, tmp3.created_on from (select tmp1.id as user_id, tmp1.created_on, tmp1.selected_date as spent_on, " + + query = "select tmp3.user_id as user_id , tmp3.spent_on as spent_on, tmp3.#{spField} as #{spField}, tmp3.status as status, tmp3.status_updater as status_updater, tmp3.created_on as created_on from (select tmp1.id as user_id, tmp1.created_on, tmp1.selected_date as spent_on, " + "case when tmp2.#{spField} is null then 0 else tmp2.#{spField} end as #{spField}, " + "case when tmp2.status is null then 'e' else tmp2.status end as status, tmp2.status_updater " query = query + " from " + dtRangeForUsrSqlStr + " left join " + teSqlStr diff --git a/app/helpers/wktime_helper.rb b/app/helpers/wktime_helper.rb index 6fa79541f..c22709a06 100644 --- a/app/helpers/wktime_helper.rb +++ b/app/helpers/wktime_helper.rb @@ -810,7 +810,7 @@ def getAddDateStr(dtfield,noOfDays) if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' dateSqlStr = "date('#{dtfield}') + " + noOfDays.to_s elsif ActiveRecord::Base.connection.adapter_name == 'SQLite' - dateSqlStr = "date('#{dtfield}' , '+' || " + noOfDays.to_s + " || ' days')" + dateSqlStr = "date('#{dtfield}' , '+' || " + "(#{noOfDays.to_s})" + " || ' days')" elsif ActiveRecord::Base.connection.adapter_name == 'SQLServer' dateSqlStr = "DateAdd(d, " + noOfDays.to_s + ",'#{dtfield}')" else @@ -943,7 +943,7 @@ def showReports end def getTEAllTimeRange(ids) - teQuery = "select v.startday from (select #{getDateSqlString('t.spent_on')} as startday " + + teQuery = "select v.startday as startday from (select #{getDateSqlString('t.spent_on')} as startday " + "from time_entries t where user_id in (#{ids})) v group by v.startday order by v.startday" teResult = TimeEntry.find_by_sql(teQuery) end @@ -977,7 +977,7 @@ def getAllTimeRange(ids, isTime) if !usrResult.blank? && usrResult.size > 0 stDate = (usrResult[0].startday) stDate = getStartDay(stDate.to_date) if !stDate.blank? && isTime - if (!stDate.blank? && stDate < @from) + if (!stDate.blank? && stDate.to_date < @from.to_date) @from = stDate end end From e2aca31c1661e6d7a87297441c165b9740d2f7c5 Mon Sep 17 00:00:00 2001 From: Karthick Date: Tue, 9 Aug 2016 15:18:21 +0530 Subject: [PATCH 17/37] Bug Fixing attendance report total hours --- app/views/wkreport/reportattn.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/wkreport/reportattn.html.erb b/app/views/wkreport/reportattn.html.erb index b318de979..ecc2b8de0 100644 --- a/app/views/wkreport/reportattn.html.erb +++ b/app/views/wkreport/reportattn.html.erb @@ -109,7 +109,7 @@ hour = @attendance_entries[entry.id.to_s + '_' + i.to_s + '_hours'] leave = @attendance_entries[entry.id.to_s + '_' + i.to_s + '_leave'] attn_entry = shortName[leave].blank? ? hour : (hour.blank? ? shortName[leave] : (hour.to_s) + "/ " + shortName[leave]) - totalhours += hour.blank? ? 0 : hour + totalhours = totalhours + (hour.blank? ? 0 : hour.to_f) %> <%=h attn_entry %> <% end -%> From 6e23adc7a8ea962e30004f38418ff103c04898ce Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 11 Aug 2016 16:38:14 +0530 Subject: [PATCH 18/37] Bug fixing filter failed in attendance leave list --- app/controllers/wkattendance_controller.rb | 16 -- .../wkimportattendance_controller.rb | 25 +++ app/helpers/wkattendance_helper.rb | 136 ---------------- app/helpers/wkimportattendance_helper.rb | 148 ++++++++++++++++++ app/views/wkattendance/_clk_index.html.erb | 13 +- app/views/wkattendance/_list.html.erb | 3 - .../new.html.erb | 0 .../show.html.erb | 2 + config/locales/de.yml | 5 +- config/locales/en.yml | 5 +- config/locales/fr.yml | 5 +- config/locales/it.yml | 5 +- config/routes.rb | 13 +- init.rb | 6 +- 14 files changed, 201 insertions(+), 181 deletions(-) create mode 100644 app/controllers/wkimportattendance_controller.rb create mode 100644 app/helpers/wkimportattendance_helper.rb rename app/views/{wkattendance => wkimportattendance}/new.html.erb (100%) rename app/views/{wkattendance => wkimportattendance}/show.html.erb (92%) diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 2d403871d..08d19b10a 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -373,20 +373,4 @@ def formPaginationCondition rangeStr end - def new - end - - def show - file = params[:file] - filePath = file.path - begin - isSuccess = importAttendance(filePath, false) - #redirect_to :action => 'show' - rescue Exception => e - @errorMsg = "Import failed: #{e.message}" - flash[:error] = @errorMsg - redirect_to :action => 'new' - end - end - end diff --git a/app/controllers/wkimportattendance_controller.rb b/app/controllers/wkimportattendance_controller.rb new file mode 100644 index 000000000..0a83089ac --- /dev/null +++ b/app/controllers/wkimportattendance_controller.rb @@ -0,0 +1,25 @@ +class WkimportattendanceController < WkattendanceController +unloadable + +include WkimportattendanceHelper + +before_filter :require_login +require 'csv' + + def new + end + + def show + file = params[:file] + filePath = file.path + begin + isSuccess = importAttendance(filePath, false) + #redirect_to :action => 'show' + rescue Exception => e + @errorMsg = "Import failed: #{e.message}" + flash[:error] = @errorMsg + redirect_to :action => 'new' + end + end + +end diff --git a/app/helpers/wkattendance_helper.rb b/app/helpers/wkattendance_helper.rb index ad1145532..2bf0d6516 100644 --- a/app/helpers/wkattendance_helper.rb +++ b/app/helpers/wkattendance_helper.rb @@ -125,136 +125,6 @@ def deleteWkUserLeaves(userId, accrualOn) end end - def importAttendance(file,isAuto) - lastAttnEntriesHash = Hash.new - @errorHash = Hash.new - @importCount = 0 - userCFHash = Hash.new - custom_fields = UserCustomField.order('name') - userIdCFHash = Hash.new - unless custom_fields.blank? - userCFHash = Hash[custom_fields.map { |cf| [cf.id, cf.name] }] - end - csv = read_file(file) - lastAttnEntries = findLastAttnEntry(false) - lastAttnEntries.each do |entry| - lastAttnEntriesHash[entry.user_id] = entry - end - columnArr = Setting.plugin_redmine_wktime['wktime_fields_in_file'] - csv.each_with_index do |row,index| - # rowValueHash - Have the data of the current row - rowValueHash = Hash.new - columnArr.each_with_index do |col,i| - case col when "user_id" - rowValueHash["user_id"] = row[i] - when "start_time","end_time" - if row_date(row[i]).is_a?(DateTime) || (row[i].blank? && col == "end_time") - rowValueHash[col] = row_date(row[i]) - else - #isValid = false - @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') - end - when "hours" - rowValueHash[col] = row[i].to_f - else - if index < 1 - cfId = col.to_i #userCFHash[col] - userIdCFHash = getUserIdCFHash(cfId) - end - if userIdCFHash[row[i]].blank? - @errorHash[index+1] = userCFHash[col.to_i] + " " + l('activerecord.errors.messages.invalid') - else - rowValueHash["user_id"] = userIdCFHash[row[i]] - end - end - end - # Check the row has any invalid entries and skip that row from import - if @errorHash[index+1].blank? - @importCount = @importCount + 1 - userId = rowValueHash["user_id"] #row[0].to_i - endEntry = nil - startEntry = getFormatedTimeEntry(rowValueHash["start_time"]) - if !rowValueHash["end_time"].blank? && (rowValueHash["end_time"] != rowValueHash["start_time"]) - endEntry = getFormatedTimeEntry(rowValueHash["end_time"]) - end - - if (columnArr.include? "end_time") && (columnArr.include? "start_time") - #Get the imported records for particular user and start_time - importedEntry = WkAttendance.where(:user_id => userId, :start_time => startEntry) - if importedEntry[0].blank? - # There is no records for the given user on the given start_time - # Insert a new record to the database - lastAttnEntriesHash[userId] = addNewAttendance(startEntry,endEntry,userId) - else - # Update the record with end Entry - if importedEntry[0].end_time.blank? && !endEntry.blank? - lastAttnEntriesHash[userId] = saveAttendance(importedEntry[0], startEntry, endEntry, userId, true) - end - end - else - # Get the imported records for particular user and entry_time - # Skip the records which is already inserted by check importedEntry[0].blank? - importedEntry = WkAttendance.where("user_id = ? AND (start_time = ? OR end_time = ?)", userId, startEntry, startEntry) - if importedEntry[0].blank? - lastAttnEntriesHash[userId] = saveAttendance(lastAttnEntriesHash[userId], startEntry, endEntry, userId, false) - end - end - end - end - if isAuto - Rails.logger.info("====== File Name = #{File.basename file}=========") - if @importCount > 0 - Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") - end - if !@errorHash.blank? && @errorHash.count > 0 - Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") - Rails.logger.info("===============================================================") - Rails.logger.info(" Row || Message ") - Rails.logger.info("===============================================================") - @errorHash.each do |item| - Rails.logger.info(" #{item[0]} || #{simple_format_without_paragraph item[1]}") - Rails.logger.info("---------------------------------------------------------------") - end - Rails.logger.info("===============================================================") - end - end - return @errorHash.blank? || @errorHash.count < 0 - end - - def read_file(file) - csv_text = File.read(file) - hasHeaders = (Setting.plugin_redmine_wktime['wktime_import_file_headers'].blank? || Setting.plugin_redmine_wktime['wktime_import_file_headers'].to_i == 0) ? false : true - csv_options = {:headers => hasHeaders} - csv_options[:encoding] = Setting.plugin_redmine_wktime['wktime_field_encoding']#'UTF-8' - separator = Setting.plugin_redmine_wktime['wktime_field_separator']#',' - csv_options[:col_sep] = separator if separator.size == 1 - wrapper = Setting.plugin_redmine_wktime['wktime_field_wrapper']#'"' - csv_options[:quote_char] = wrapper if wrapper.size == 1 - csv = CSV.parse(csv_text, csv_options) - csv - end - - def getFormatedTimeEntry(entryDateTime) - entryDateTime = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) - entryTime = Time.parse("#{entryDateTime.utc.to_date.to_s} #{entryDateTime.utc.to_time.to_s} ").localtime - entryTime - end - - def getUserIdCFHash(cfId) - cfValHash = Hash.new - cfValue = CustomValue.where("custom_field_id = #{cfId}") - unless cfValue.blank? - #cfs = custom_fields.collect {|cf| userCFHash[cf.name] = cf.id } - cfValHash = Hash[cfValue.map { |cfv| [cfv.value, cfv.customized_id] }] - end - cfValHash - end - - def row_date(dateTimeStr) - format = Setting.plugin_redmine_wktime['wktime_field_datetime']#"%Y-%m-%d %T" - DateTime.strptime(dateTimeStr, format) rescue dateTimeStr - end - def addNewAttendance(startEntry,endEntry,userId) wkattendance = WkAttendance.new wkattendance.start_time = startEntry @@ -291,11 +161,5 @@ def saveAttendance(attnObj, startTime, endTime, userId, hasStartEnd) end wkattendance end - - def calcSchdulerInterval - interval = (Setting.plugin_redmine_wktime['wktime_auto_import_time_hr'].to_i*60) + (Setting.plugin_redmine_wktime['wktime_auto_import_time_min'].to_i) - intervalMin = interval>0 ? interval.to_s + 'm' : '60m' - intervalMin - end end diff --git a/app/helpers/wkimportattendance_helper.rb b/app/helpers/wkimportattendance_helper.rb new file mode 100644 index 000000000..9ff2d37fe --- /dev/null +++ b/app/helpers/wkimportattendance_helper.rb @@ -0,0 +1,148 @@ +module WkimportattendanceHelper + include WktimeHelper + include WkattendanceHelper + require 'csv' + #Copied from UserHelper + + def importAttendance(file,isAuto) + lastAttnEntriesHash = Hash.new + @errorHash = Hash.new + @importCount = 0 + userCFHash = Hash.new + custom_fields = UserCustomField.order('name') + userIdCFHash = Hash.new + unless custom_fields.blank? + userCFHash = Hash[custom_fields.map { |cf| [cf.id, cf.name] }] + end + csv = read_file(file) + lastAttnEntries = findLastAttnEntry(false) + lastAttnEntries.each do |entry| + lastAttnEntriesHash[entry.user_id] = entry + end + columnArr = Setting.plugin_redmine_wktime['wktime_fields_in_file'] + if !(csv.length > 0) + @errorMsg = l('error_no_record_to_import') + end + csv.each_with_index do |row,index| + # rowValueHash - Have the data of the current row + rowValueHash = Hash.new + columnArr.each_with_index do |col,i| + case col when "user_id" + rowValueHash["user_id"] = row[i] + when "start_time","end_time" + if row_date(row[i]).is_a?(DateTime) || (row[i].blank? && col == "end_time") + rowValueHash[col] = row_date(row[i]) + else + #isValid = false + @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + end + when "hours" + rowValueHash[col] = row[i].to_f + else + if index < 1 + cfId = col.to_i #userCFHash[col] + userIdCFHash = getUserIdCFHash(cfId) + end + if userIdCFHash[row[i]].blank? + @errorHash[index+1] = userCFHash[col.to_i] + " " + l('activerecord.errors.messages.invalid') + else + rowValueHash["user_id"] = userIdCFHash[row[i]] + end + end + end + # Check the row has any invalid entries and skip that row from import + if @errorHash[index+1].blank? + @importCount = @importCount + 1 + userId = rowValueHash["user_id"] #row[0].to_i + endEntry = nil + startEntry = getFormatedTimeEntry(rowValueHash["start_time"]) + if !rowValueHash["end_time"].blank? && (rowValueHash["end_time"] != rowValueHash["start_time"]) + endEntry = getFormatedTimeEntry(rowValueHash["end_time"]) + end + + if (columnArr.include? "end_time") && (columnArr.include? "start_time") + #Get the imported records for particular user and start_time + importedEntry = WkAttendance.where(:user_id => userId, :start_time => startEntry) + if importedEntry[0].blank? + # There is no records for the given user on the given start_time + # Insert a new record to the database + lastAttnEntriesHash[userId] = addNewAttendance(startEntry,endEntry,userId) + else + # Update the record with end Entry + if importedEntry[0].end_time.blank? && !endEntry.blank? + lastAttnEntriesHash[userId] = saveAttendance(importedEntry[0], startEntry, endEntry, userId, true) + end + end + else + # Get the imported records for particular user and entry_time + # Skip the records which is already inserted by check importedEntry[0].blank? + importedEntry = WkAttendance.where("user_id = ? AND (start_time = ? OR end_time = ?)", userId, startEntry, startEntry) + if importedEntry[0].blank? + lastAttnEntriesHash[userId] = saveAttendance(lastAttnEntriesHash[userId], startEntry, endEntry, userId, false) + end + end + end + end + Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") + Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") + if isAuto + Rails.logger.info("====== File Name = #{File.basename file}=========") + if @importCount > 0 + Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") + end + if !@errorHash.blank? && @errorHash.count > 0 + Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") + Rails.logger.info("===============================================================") + Rails.logger.info(" Row || Message ") + Rails.logger.info("===============================================================") + @errorHash.each do |item| + Rails.logger.info(" #{item[0]} || #{simple_format_without_paragraph item[1]}") + Rails.logger.info("---------------------------------------------------------------") + end + Rails.logger.info("===============================================================") + end + end + return @errorHash.blank? || @errorHash.count < 0 + end + + def read_file(file) + csv_text = File.read(file) + hasHeaders = (Setting.plugin_redmine_wktime['wktime_import_file_headers'].blank? || Setting.plugin_redmine_wktime['wktime_import_file_headers'].to_i == 0) ? false : true + csv_options = {:headers => hasHeaders} + csv_options[:encoding] = Setting.plugin_redmine_wktime['wktime_field_encoding']#'UTF-8' + separator = Setting.plugin_redmine_wktime['wktime_field_separator']#',' + csv_options[:col_sep] = separator if separator.size == 1 + wrapper = Setting.plugin_redmine_wktime['wktime_field_wrapper']#'"' + csv_options[:quote_char] = wrapper if wrapper.size == 1 + csv = CSV.parse(csv_text, csv_options) + csv + end + + def getFormatedTimeEntry(entryDateTime) + entryDateTime = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) + entryTime = Time.parse("#{entryDateTime.utc.to_date.to_s} #{entryDateTime.utc.to_time.to_s} ").localtime + entryTime + end + + def getUserIdCFHash(cfId) + cfValHash = Hash.new + cfValue = CustomValue.where("custom_field_id = #{cfId}") + unless cfValue.blank? + #cfs = custom_fields.collect {|cf| userCFHash[cf.name] = cf.id } + cfValHash = Hash[cfValue.map { |cfv| [cfv.value, cfv.customized_id] }] + end + cfValHash + end + + def row_date(dateTimeStr) + format = Setting.plugin_redmine_wktime['wktime_field_datetime']#"%Y-%m-%d %T" + DateTime.strptime(dateTimeStr, format) rescue dateTimeStr + end + + def calcSchdulerInterval + interval = (Setting.plugin_redmine_wktime['wktime_auto_import_time_hr'].to_i*60) + (Setting.plugin_redmine_wktime['wktime_auto_import_time_min'].to_i) + intervalMin = interval>0 ? interval.to_s + 'm' : '60m' + intervalMin + end + +end diff --git a/app/views/wkattendance/_clk_index.html.erb b/app/views/wkattendance/_clk_index.html.erb index 16d6bed17..fbe3569ad 100644 --- a/app/views/wkattendance/_clk_index.html.erb +++ b/app/views/wkattendance/_clk_index.html.erb @@ -7,14 +7,16 @@ //getMembersbyGroup <%= hidden_field_tag 'back_url', url_for(params) %> +
+<%= link_to l(:"label_import_attendance"), url_for(:controller => "wkimportattendance", :action => 'new', :tab => controller.controller_name)%> +
<% wktime_helper = Object.new.extend(WktimeHelper) %> <%= form_tag({:controller => controller_name, :action => 'clockindex'}, :method => :get, :id => 'query_form') do %> <%=h hidden_field_tag('tab', "clock") %> <%= hidden_field_tag "searchlist", "#{controller_name}" %> <% groupid =session[:wkattendance][:group_id] userid =session[:wkattendance][:user_id] %> -
- +
<% if User.current.admin? || isAccountUser %> @@ -34,13 +36,10 @@ :style=> "width:200px;") %> <% end %> -
<%=l(:label_group_plural)%>
- - <%= render :partial => 'wkattendance/date_range' %> -
+ + <%= render :partial => 'wkattendance/date_range' %> <% end %>   - <%= render :partial => 'wkattendance/clk_list'%> <%= pagination_links_full @entry_pages, @entry_count %> <%=h hidden_field_tag('tab', "#{controller_name}") %> diff --git a/app/views/wkattendance/_list.html.erb b/app/views/wkattendance/_list.html.erb index 70b00ec76..f2aab12d3 100644 --- a/app/views/wkattendance/_list.html.erb +++ b/app/views/wkattendance/_list.html.erb @@ -6,9 +6,6 @@
<%= link_to l(:"button_populate_leave"), url_for(:controller => controller_name, :action => 'runPeriodEndProcess', :tab => controller.controller_name), :data => {:confirm => l(:text_are_you_sure_want_to_run)}%>
-
-<%= link_to l(:"label_import_attendance"), url_for(:controller => controller_name, :action => 'new', :tab => controller.controller_name)%> -
<%= form_tag({:controller => controller_name, :action => 'index'}, :method => :get) do %>
<%= l(:label_filter_plural) %> diff --git a/app/views/wkattendance/new.html.erb b/app/views/wkimportattendance/new.html.erb similarity index 100% rename from app/views/wkattendance/new.html.erb rename to app/views/wkimportattendance/new.html.erb diff --git a/app/views/wkattendance/show.html.erb b/app/views/wkimportattendance/show.html.erb similarity index 92% rename from app/views/wkattendance/show.html.erb rename to app/views/wkimportattendance/show.html.erb index 9a1f3591b..21fa15a0e 100644 --- a/app/views/wkattendance/show.html.erb +++ b/app/views/wkimportattendance/show.html.erb @@ -24,4 +24,6 @@ <% end %> +<% else %> +

<%= @errorMsg %>

<% end %> \ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml index 39fc70417..8d1e44217 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -200,7 +200,7 @@ de: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance + label_import_attendance: Import Attendance label_path: Import file path label_auto_import: Auto Import label_auto_import_time: Auto Import Every @@ -209,4 +209,5 @@ de: label_user_id: Userid label_available_fields: Available Fields label_fields_in_file: Fields in File - label_import_file_headers: File Headers \ No newline at end of file + label_import_file_headers: File Headers + error_no_record_to_import: No Record to Import \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index dcbc20be2..8c5bb9a22 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -201,7 +201,7 @@ en: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: Clock in/out label_hours: Hours - label_import_attendance: Import attendance + label_import_attendance: Import Attendance label_path: Import file path label_auto_import: Auto Import label_auto_import_time: Auto Import Every @@ -210,4 +210,5 @@ en: label_user_id: Userid label_available_fields: Available Fields label_fields_in_file: Fields in File - label_import_file_headers: File Headers \ No newline at end of file + label_import_file_headers: File Headers + error_no_record_to_import: No Record to Import \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 5478463d5..50210b344 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -201,7 +201,7 @@ fr: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance + label_import_attendance: Import Attendance label_path: Import file path label_auto_import: Auto Import label_auto_import_time: Auto Import Every @@ -210,4 +210,5 @@ fr: label_user_id: Userid label_available_fields: Available Fields label_fields_in_file: Fields in File - label_import_file_headers: File Headers \ No newline at end of file + label_import_file_headers: File Headers + error_no_record_to_import: No Record to Import \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index d142e496f..dc2382fc8 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -198,7 +198,7 @@ it: text_are_you_sure_want_to_run: "Are you sure you want to run this process ?" label_clock: clock in/out label_hours: Hours - label_import_attendance: Import attendance + label_import_attendance: Import Attendance label_path: Import file path label_auto_import: Auto Import label_auto_import_time: Auto Import Every @@ -207,4 +207,5 @@ it: label_user_id: Userid label_available_fields: Available Fields label_fields_in_file: Fields in File - label_import_file_headers: File Headers \ No newline at end of file + label_import_file_headers: File Headers + error_no_record_to_import: No Record to Import \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index ceb83b249..79d83239c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -87,8 +87,10 @@ end #For Attendance - resources :wk_attendances, :controller => 'wkattendance' do - collection { post :show } + resources :wk_attendances, :controller => 'wkimportattendance' do + collection do + post 'show' + end end get 'wkattendance/index', :to => 'wkattendance#index' @@ -123,9 +125,4 @@ get 'wkreport/getMembersbyGroup', :to => 'wkreport#getMembersbyGroup' - get 'wkattendance/runPeriodEndProcess', :to => 'wkattendance#runPeriodEndProcess' - - post 'wkattendance/manualImport', :to => 'wkattendance#manualImport' - - get 'wkattendance/new', :to => 'wkattendance#new' - \ No newline at end of file + get 'wkattendance/runPeriodEndProcess', :to => 'wkattendance#runPeriodEndProcess' \ No newline at end of file diff --git a/init.rb b/init.rb index 7842e22b3..90ad8508e 100644 --- a/init.rb +++ b/init.rb @@ -306,8 +306,8 @@ def destroy if (!Setting.plugin_redmine_wktime['wktime_auto_import'].blank? && Setting.plugin_redmine_wktime['wktime_auto_import'].to_i == 1) require 'rufus/scheduler' importScheduler = Rufus::Scheduler.new - wkattn_helper = Object.new.extend(WkattendanceHelper) - intervalMin = wkattn_helper.calcSchdulerInterval + import_helper = Object.new.extend(WkimportattendanceHelper) + intervalMin = import_helper.calcSchdulerInterval #Scheduler will run at every intervalMin importScheduler.every intervalMin do begin @@ -317,7 +317,7 @@ def destroy sortedFilesArr = Dir.entries(filePath).sort_by { |x| File.mtime(filePath + "/" + x) } sortedFilesArr.each do |filename| next if File.directory? filePath + "/" + filename - isSuccess = wkattn_helper.importAttendance(filePath + "/" + filename, true ) + isSuccess = import_helper.importAttendance(filePath + "/" + filename, true ) if !Dir.exists?("Processed") FileUtils::mkdir_p filePath+'/Processed'#Dir.mkdir("Processed") end From b87f002efb0a5b32056129539dd7cb4fe918507f Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Thu, 11 Aug 2016 17:15:48 +0530 Subject: [PATCH 19/37] bug: Validate clock in & Clock out for null & maximum --- assets/javascripts/edit.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/assets/javascripts/edit.js b/assets/javascripts/edit.js index 9cb8f436b..4b31ee0bd 100644 --- a/assets/javascripts/edit.js +++ b/assets/javascripts/edit.js @@ -1276,14 +1276,20 @@ function validateHr(hrFld,day, element) hrFld.value = "0:00"; hrVal = "0:00"; } - - + clkinTime = convertTimeToSec(document.getElementById(element[0]).value); + clkoutTime = convertTimeToSec(document.getElementById(element[1]).value); if(hrVal.match(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/) == null) { hrFld.value = hrFld.defaultValue; alert("Not a valid time format"); } - else + else if((clkinTime > clkoutTime) || ( isNaN(clkinTime) && !isNaN(clkoutTime) ) ) + { + var msg = ( isNaN(clkinTime) && !isNaN(clkoutTime) ) ? "Please enter Clock in." : "The Clock in time can't be greater then clock out."; + hrFld.value = hrFld.defaultValue; + alert(msg); + } + else if( !isNaN(clkinTime) && !isNaN(clkoutTime) ) { if(element[3] != null && element[3] ) { From b3c6a480d37f1feaafa3185170d917ed01347fbd Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 11 Aug 2016 18:59:10 +0530 Subject: [PATCH 20/37] Date picker not shown in redmine 3.3.0 --- app/views/wkattendance/_date_range.html.erb | 5 +++-- app/views/wkreport/_date_range.html.erb | 5 +++-- app/views/wktime/_date_range.html.erb | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/views/wkattendance/_date_range.html.erb b/app/views/wkattendance/_date_range.html.erb index d52115764..085953bc4 100644 --- a/app/views/wkattendance/_date_range.html.erb +++ b/app/views/wkattendance/_date_range.html.erb @@ -13,8 +13,9 @@
<%= radio_button_tag 'period_type', '2', @free_period, :onclick => '$("#from,#to").removeAttr("disabled");$("#period").attr("disabled", true);' %> -<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), - :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))).html_safe %> +<%= l(:label_date_from_to, :start => ( date_field_tag('from', @from, {:id => 'from', :size => 10, :disabled => !@free_period}) + + calendar_for('from')), :end => ( date_field_tag('to', @to, {:id => 'to', :size => 10, :disabled => !@free_period}) + + calendar_for('to'))).html_safe %>
diff --git a/app/views/wkreport/_date_range.html.erb b/app/views/wkreport/_date_range.html.erb index 4378162e8..09434d43a 100644 --- a/app/views/wkreport/_date_range.html.erb +++ b/app/views/wkreport/_date_range.html.erb @@ -13,8 +13,9 @@
<%= radio_button_tag 'period_type', '2', @free_period, :onclick => '$("#from,#to").removeAttr("disabled");$("#period").attr("disabled", true);' %> -<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), - :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))).html_safe %> +<%= l(:label_date_from_to, :start => ( date_field_tag('from', @from, {:id => 'from', :size => 10, :disabled => !@free_period}) + + calendar_for('from')), :end => ( date_field_tag('to', @to, {:id => 'to', :size => 10, :disabled => !@free_period}) + + calendar_for('to'))).html_safe %>
diff --git a/app/views/wktime/_date_range.html.erb b/app/views/wktime/_date_range.html.erb index 340da622e..000a3e353 100644 --- a/app/views/wktime/_date_range.html.erb +++ b/app/views/wktime/_date_range.html.erb @@ -21,8 +21,9 @@
<%= radio_button_tag 'period_type', '2', @free_period, :onclick => '$("#from,#to").removeAttr("disabled");$("#period").attr("disabled", true);' %> -<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), - :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))).html_safe %> +<%= l(:label_date_from_to, :start => ( date_field_tag('from', @from, {:id => 'from', :size => 10, :disabled => !@free_period}) + + calendar_for('from')), :end => ( date_field_tag('to', @to, {:id => 'to', :size => 10, :disabled => !@free_period}) + + calendar_for('to'))).html_safe %>
From a6bbf340e33a3697f0fe55a3c50dfd0361d13f7a Mon Sep 17 00:00:00 2001 From: Karthick Date: Fri, 12 Aug 2016 10:51:08 +0530 Subject: [PATCH 21/37] Filter show result for default value in clockin/out tab when seesion value set in the filter --- app/controllers/wkattendance_controller.rb | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 08d19b10a..61963eeb7 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -52,12 +52,16 @@ def clockindex userIds << users.id end ids = nil - if params[:user_id].blank? && params[:user_id] != 0 - ids = User.current.id - elsif params[:user_id].to_i != 0 && params[:group_id].to_i == 0 - ids = params[:user_id].to_i - elsif params[:group_id].to_i != 0 - ids = params[:user_id].to_i == 0 ? (userIds.blank? ? 0 : userIds.join(',')) : params[:user_id].to_i + user_id = session[:wkattendance][:user_id] + group_id = session[:wkattendance][:group_id] + status = session[:wkattendance][:status] + + if user_id.blank? + ids = User.current.id + elsif user_id.to_i != 0 && group_id.to_i == 0 + ids = user_id.to_i + elsif group_id.to_i != 0 + ids =user_id.to_i == 0 ? (userIds.blank? ? 0 : userIds.join(',')) : user_id.to_i else ids = userIds.join(',') end @@ -77,14 +81,7 @@ def clockindex WHERE v.selected_date between '#{@from}' and '#{@to}' order by u.id, v.selected_date) vw left join (select min(start_time) as start_time, max(end_time) as end_time, " + getConvertDateStr('start_time') + " entry_date,sum(hours) as hours, user_id from wk_attendances WHERE " + getConvertDateStr('start_time') +" between '#{@from}' and '#{@to}' - group by user_id, " + getConvertDateStr('start_time') + ") evw on (vw.selected_date = evw.entry_date and vw.id = evw.user_id)" - if params[:user_id].blank? && params[:user_id] != 0 - sqlQuery += "where vw.id in(#{User.current.id}) " - elsif params[:user_id].to_i != 0 && params[:group_id].to_i == 0 - sqlQuery += "where vw.id in(#{params[:user_id].to_i}) " - elsif params[:group_id].to_i != 0 - sqlQuery += "where vw.id in(#{params[:user_id].to_i == 0 ? (userIds.blank? ? 0 : userIds.join(',')) : params[:user_id].to_i }) " - end + group by user_id, " + getConvertDateStr('start_time') + ") evw on (vw.selected_date = evw.entry_date and vw.id = evw.user_id) where vw.id in(#{ids}) " findBySql(sqlQuery, WkAttendance) end From ba31aca364a1647e32dd8b1921a442aaf8e3972e Mon Sep 17 00:00:00 2001 From: Karthick Date: Fri, 12 Aug 2016 10:52:23 +0530 Subject: [PATCH 22/37] Allign settings in attendance settings tab --- app/views/settings/_tab_attendance.html.erb | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/views/settings/_tab_attendance.html.erb b/app/views/settings/_tab_attendance.html.erb index ee25e86e2..c2ddf2016 100644 --- a/app/views/settings/_tab_attendance.html.erb +++ b/app/views/settings/_tab_attendance.html.erb @@ -223,9 +223,32 @@ lblYear = "<%=l(:label_year) %>";
<%= l(:button_import) %> + <%= l(:label_redmine_restart_warning) %>

<%= check_box_tag('settings[wktime_auto_import]', 1, @settings['wktime_auto_import'].to_i == 1) %>

+

+ + <% + hr = [] + for i in 0..23 + if i < 10 + hr << ['0' + i.to_s,i] + else + hr << [i,i] + end + end + %> + <%= l(:field_hours) %> <%= select_tag('settings[wktime_auto_import_time_hr]', options_for_select(hr, + :selected => @settings['wktime_auto_import_time_hr'].blank? ? 23 : @settings['wktime_auto_import_time_hr']))%> + <%= l(:label_wk_minutes) %> <%= select_tag('settings[wktime_auto_import_time_min]', options_for_select([['00',0], + [15, 15], + [30, 30], + [45, 45]], :selected => @settings['wktime_auto_import_time_min'].blank? ? 0 : @settings['wktime_auto_import_time_min']))%> +

+

+ <%= text_field_tag 'settings[wktime_file_to_import]', @settings['wktime_file_to_import'], :size => 40 %> +

<%= check_box_tag('settings[wktime_import_file_headers]', 1, @settings['wktime_import_file_headers'].to_i == 1) %>

@@ -274,29 +297,6 @@ lblYear = "<%=l(:label_year) %>"; - -

- - <% - hr = [] - for i in 0..23 - if i < 10 - hr << ['0' + i.to_s,i] - else - hr << [i,i] - end - end - %> - <%= l(:field_hours) %> <%= select_tag('settings[wktime_auto_import_time_hr]', options_for_select(hr, - :selected => @settings['wktime_auto_import_time_hr'].blank? ? 23 : @settings['wktime_auto_import_time_hr']))%> - <%= l(:label_wk_minutes) %> <%= select_tag('settings[wktime_auto_import_time_min]', options_for_select([['00',0], - [15, 15], - [30, 30], - [45, 45]], :selected => @settings['wktime_auto_import_time_min'].blank? ? 0 : @settings['wktime_auto_import_time_min']))%> -

-

- <%= text_field_tag 'settings[wktime_file_to_import]', @settings['wktime_file_to_import'], :size => 50 %> -

<% if !projArr.blank? %>
From 25961625ef403a75c6f2d88e093ef3cc3c9d2ffc Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Fri, 12 Aug 2016 10:56:21 +0530 Subject: [PATCH 23/37] Bug: Attendances Clock in/out save --- app/controllers/wkattendance_controller.rb | 37 ++++++++++++++++++++++ app/controllers/wktime_controller.rb | 2 +- app/views/wkattendance/_clk_list.html.erb | 2 +- app/views/wkattendance/clockedit.html.erb | 6 ++-- app/views/wkattendance/edit.html.erb | 2 +- assets/javascripts/wkstatus.js | 4 +-- config/routes.rb | 2 ++ 7 files changed, 48 insertions(+), 7 deletions(-) diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 61963eeb7..3107e513c 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -3,6 +3,7 @@ class WkattendanceController < WkbaseController include WktimeHelper include WkattendanceHelper +include WkimportattendanceHelper before_filter :require_login before_filter :check_perm_and_redirect, :only => [:edit, :update] @@ -370,4 +371,40 @@ def formPaginationCondition rangeStr end + def saveClockInOut + errorMsg =nil + sucessMsg = nil + for i in 0..params[:attnDayEntriesCnt].to_i-1 + starttime = params[:startdate] + " " + params["attnstarttime#{i}"] + ":00" + entry_start_time = DateTime.strptime(starttime, "%Y-%m-%d %T") rescue starttime + endtime = params[:startdate] + " " + params["attnendtime#{i}"] + ":00" + entry_end_time = DateTime.strptime(endtime, "%Y-%m-%d %T") rescue endtime + if !params["attnEntriesId#{i}"].blank? + wkattendance = WkAttendance.find(params["attnEntriesId#{i}"].to_i) + wkattendance.start_time = getFormatedTimeEntry(entry_start_time) + wkattendance.end_time = getFormatedTimeEntry(entry_end_time) + wkattendance.hours = computeWorkedHours(wkattendance.start_time, wkattendance.end_time, true) + wkattendance.save() + sucessMsg = l(:notice_successful_update) + else + addNewAttendance(getFormatedTimeEntry(entry_start_time),getFormatedTimeEntry(entry_end_time), params[:user_id].to_i) + sucessMsg = l(:notice_successful_update) + end + + if params["attnstarttime#{i}"] == '0:00' && params["attnendtime#{i}"] == '0:00' + wkattendance.destroy() + sucessMsg = l(:notice_successful_delete) + end + end + + if errorMsg.nil? + redirect_to :controller => 'wkattendance',:action => 'clockindex' , :tab => 'clock' + flash[:notice] = sucessMsg #l(:notice_successful_update) + else + flash[:error] = errorMsg + redirect_to :action => 'edit' + end + end + + end diff --git a/app/controllers/wktime_controller.rb b/app/controllers/wktime_controller.rb index 1373676f2..2f4e7b2f3 100644 --- a/app/controllers/wktime_controller.rb +++ b/app/controllers/wktime_controller.rb @@ -876,7 +876,7 @@ def updateAttendance entryvalues[2] = "00:00" entryvalues[3] = oldendvalue end - entrydate = to_boolean(params[:isdate]) ? params[:startdate] : @startday + ((entryvalues[1].to_i)- 1) + entrydate = @startday + ((entryvalues[1].to_i)- 1) #to_boolean(params[:isdate]) ? params[:startdate] : @startday + ((entryvalues[1].to_i)- 1) wkattendance.user_id = params[:user_id].to_i wkattendance.start_time = !entryvalues[2].blank? ? Time.parse("#{entrydate.to_s} #{ entryvalues[2].to_s}:00 ").localtime.to_s : '00:00' if !entryvalues[3].blank? diff --git a/app/views/wkattendance/_clk_list.html.erb b/app/views/wkattendance/_clk_list.html.erb index 041277910..58548672a 100644 --- a/app/views/wkattendance/_clk_list.html.erb +++ b/app/views/wkattendance/_clk_list.html.erb @@ -20,7 +20,7 @@ <%=h entry.entry_date %> <%=h !entry.start_time ? "" : entry.start_time.localtime.strftime('%r') %> <%=h !entry.end_time ? "" : entry.end_time.localtime.strftime('%r') %> -<%=h !entry.hours ? "" : entry.hours %> +<%=h !entry.hours ? "" : (entry.hours).round(2) %> <%= link_to image_tag('edit.png'), {:controller => controller.controller_name, :action => 'clockedit', :user_id => entry.user_id, :date => entry.entry_date, :tab => controller.controller_name}, :title => l(:button_edit) %> diff --git a/app/views/wkattendance/clockedit.html.erb b/app/views/wkattendance/clockedit.html.erb index c568b729b..419590579 100644 --- a/app/views/wkattendance/clockedit.html.erb +++ b/app/views/wkattendance/clockedit.html.erb @@ -1,4 +1,5 @@ <%= javascript_include_tag 'edit', :plugin => "redmine_wktime" %> +<%= form_tag({:controller => 'wkattendance', :action => 'saveClockInOut'}, :method => :post, :id => 'save_ClockInOut') do %>

<%= l(:label_clock) + " " + l(:field_summary) %>

@@ -80,6 +81,7 @@

- <%= submit_tag l(:button_save), :onclick => " updateAttendance();", :hidden => isAccountUser ? false : true, :id => 'wkattendance_save', :disabled => false %>

+ <%= submit_tag l(:button_save), :hidden => isAccountUser ? false : true, :id => 'wkattendance_save', :disabled => false %>

- \ No newline at end of file + +<% end %> \ No newline at end of file diff --git a/app/views/wkattendance/edit.html.erb b/app/views/wkattendance/edit.html.erb index f9d1dc734..597479d86 100644 --- a/app/views/wkattendance/edit.html.erb +++ b/app/views/wkattendance/edit.html.erb @@ -1,4 +1,4 @@ -<%= form_tag({:controller => 'wkattendance', :action => 'update'}, :method => :post, :id => 'wkattendance_update') do %> +<%= form_tag({:controller => 'wkattendance', :action => 'update'}, :method => :post, :id => 'query_form') do %> <% lastAccrualOn = Date.civil(Date.today.year, Date.today.month, 1) -1 accrual_on = params[:accrual_on].to_s.to_date diff --git a/assets/javascripts/wkstatus.js b/assets/javascripts/wkstatus.js index cd7318aec..1dafe0531 100644 --- a/assets/javascripts/wkstatus.js +++ b/assets/javascripts/wkstatus.js @@ -152,7 +152,7 @@ function showIssueMessage(data,divID) { divID.style.display = 'none'; } } - +/* function updateAttendance() { var attnEntriesId, attnStartTime, attnEndTime, attnhours; @@ -188,7 +188,7 @@ function updateAttendance() }); } - +*/ function signAttendance(str) { var d = new Date(); diff --git a/config/routes.rb b/config/routes.rb index 79d83239c..3d75dfef0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -114,6 +114,8 @@ get 'wkattendance/getMembersbyGroup', :to => 'wkattendance#getMembersbyGroup' + post 'wkattendance/saveClockInOut', :to => 'wkattendance#saveClockInOut' + #For Report get 'wkreport/index', :to => 'wkreport#index' From 89025277e3bf46234ddbf64cc27e1103876d807e Mon Sep 17 00:00:00 2001 From: Karthick Date: Fri, 12 Aug 2016 04:52:34 +0530 Subject: [PATCH 24/37] Import attendance timezone issue --- app/controllers/wkbase_controller.rb | 2 +- app/helpers/wkattendance_helper.rb | 4 ++-- app/helpers/wkimportattendance_helper.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/wkbase_controller.rb b/app/controllers/wkbase_controller.rb index ac2fecca0..2710b238d 100644 --- a/app/controllers/wkbase_controller.rb +++ b/app/controllers/wkbase_controller.rb @@ -8,7 +8,7 @@ def updateClockInOut @lastAttnEntry = lastAttnEntries[0] end currentDate = (DateTime.parse params[:startdate]) - entryTime = Time.parse("#{currentDate.utc.to_date.to_s} #{currentDate.utc.to_time.to_s} ").localtime + entryTime = Time.parse("#{currentDate.to_date.to_s} #{currentDate.utc.to_time.to_s} ").localtime @lastAttnEntry = saveAttendance(@lastAttnEntry, entryTime, nil, User.current.id, false) ret = 'done' respond_to do |format| diff --git a/app/helpers/wkattendance_helper.rb b/app/helpers/wkattendance_helper.rb index 2bf0d6516..5acee5567 100644 --- a/app/helpers/wkattendance_helper.rb +++ b/app/helpers/wkattendance_helper.rb @@ -137,11 +137,11 @@ def addNewAttendance(startEntry,endEntry,userId) def saveAttendance(attnObj, startTime, endTime, userId, hasStartEnd) wkattendance = nil - if(!attnObj.blank? && ((attnObj.end_time.blank? && attnObj.start_time > (startTime - 1.day) )|| hasStartEnd)) + if(!attnObj.blank? && ((attnObj.end_time.blank? && ((startTime - attnObj.start_time.localtime)/3600) < 24 )|| hasStartEnd)) if !hasStartEnd entrydate = attnObj.start_time start_local = entrydate.localtime - if ((startTime.to_date) != attnObj.start_time.to_date) + if ((startTime.localtime.to_date) != attnObj.start_time.localtime.to_date) endtime = start_local.change({ hour: "23:59".to_time.strftime("%H"), min: "23:59".to_time.strftime("%M"), sec: '59' }) nextDayStart = Time.parse("#{startTime.to_date.to_s} 00:00:00 ").localtime.to_s wkattendance = addNewAttendance(nextDayStart,startTime,userId) diff --git a/app/helpers/wkimportattendance_helper.rb b/app/helpers/wkimportattendance_helper.rb index 9ff2d37fe..5bbdbcb9a 100644 --- a/app/helpers/wkimportattendance_helper.rb +++ b/app/helpers/wkimportattendance_helper.rb @@ -119,8 +119,8 @@ def read_file(file) end def getFormatedTimeEntry(entryDateTime) - entryDateTime = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) - entryTime = Time.parse("#{entryDateTime.utc.to_date.to_s} #{entryDateTime.utc.to_time.to_s} ").localtime + entryLocal = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) + entryTime = Time.parse("#{entryLocal.to_date.to_s} #{entryLocal.utc.to_time.to_s} ").localtime entryTime end From ebbfc07ab0ca13a58504c031461ebe43818de6d2 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Fri, 12 Aug 2016 17:13:23 +0530 Subject: [PATCH 25/37] bug fixing: Clock in/out and Version change --- app/controllers/wkattendance_controller.rb | 38 ++++++++++++---------- app/helpers/wkimportattendance_helper.rb | 7 ++-- app/views/wkattendance/clockedit.html.erb | 8 ++--- app/views/wkreport/reportattn.html.erb | 2 +- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/it.yml | 2 +- init.rb | 2 +- 9 files changed, 35 insertions(+), 30 deletions(-) diff --git a/app/controllers/wkattendance_controller.rb b/app/controllers/wkattendance_controller.rb index 3107e513c..c6e8fdf7b 100644 --- a/app/controllers/wkattendance_controller.rb +++ b/app/controllers/wkattendance_controller.rb @@ -374,26 +374,28 @@ def formPaginationCondition def saveClockInOut errorMsg =nil sucessMsg = nil + endtime = nil for i in 0..params[:attnDayEntriesCnt].to_i-1 - starttime = params[:startdate] + " " + params["attnstarttime#{i}"] + ":00" - entry_start_time = DateTime.strptime(starttime, "%Y-%m-%d %T") rescue starttime - endtime = params[:startdate] + " " + params["attnendtime#{i}"] + ":00" - entry_end_time = DateTime.strptime(endtime, "%Y-%m-%d %T") rescue endtime - if !params["attnEntriesId#{i}"].blank? - wkattendance = WkAttendance.find(params["attnEntriesId#{i}"].to_i) - wkattendance.start_time = getFormatedTimeEntry(entry_start_time) - wkattendance.end_time = getFormatedTimeEntry(entry_end_time) - wkattendance.hours = computeWorkedHours(wkattendance.start_time, wkattendance.end_time, true) - wkattendance.save() - sucessMsg = l(:notice_successful_update) - else - addNewAttendance(getFormatedTimeEntry(entry_start_time),getFormatedTimeEntry(entry_end_time), params[:user_id].to_i) - sucessMsg = l(:notice_successful_update) - end - - if params["attnstarttime#{i}"] == '0:00' && params["attnendtime#{i}"] == '0:00' + starttime = params[:startdate] + " " + params["attnstarttime#{i}"] + ":00" + entry_start_time = DateTime.strptime(starttime, "%Y-%m-%d %T") rescue starttime + endtime = params[:startdate] + " " + params["attnendtime#{i}"] + ":00" if !params["attnendtime#{i}"].blank? + entry_end_time = DateTime.strptime(endtime, "%Y-%m-%d %T") rescue endtime + if params["attnstarttime#{i}"] == '0:00' && params["attnendtime#{i}"] == '0:00' + wkattendance = WkAttendance.find(params["attnEntriesId#{i}"].to_i) if !params["attnEntriesId#{i}"].blank? wkattendance.destroy() - sucessMsg = l(:notice_successful_delete) + sucessMsg = l(:notice_successful_delete) + else + if !params["attnEntriesId#{i}"].blank? + wkattendance = WkAttendance.find(params["attnEntriesId#{i}"].to_i) + wkattendance.start_time = getFormatedTimeEntry(entry_start_time) + wkattendance.end_time = getFormatedTimeEntry(entry_end_time) #if !entry_end_time.blank? + wkattendance.hours = computeWorkedHours(wkattendance.start_time, wkattendance.end_time, true) if !wkattendance.end_time.blank? + wkattendance.save() + sucessMsg = l(:notice_successful_update) + else + addNewAttendance(getFormatedTimeEntry(entry_start_time),getFormatedTimeEntry(entry_end_time), params[:user_id].to_i) + sucessMsg = l(:notice_successful_update) + end end end diff --git a/app/helpers/wkimportattendance_helper.rb b/app/helpers/wkimportattendance_helper.rb index 5bbdbcb9a..fb50dd9ef 100644 --- a/app/helpers/wkimportattendance_helper.rb +++ b/app/helpers/wkimportattendance_helper.rb @@ -119,8 +119,11 @@ def read_file(file) end def getFormatedTimeEntry(entryDateTime) - entryLocal = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) - entryTime = Time.parse("#{entryLocal.to_date.to_s} #{entryLocal.utc.to_time.to_s} ").localtime + entryTime = nil + if !entryDateTime.blank? + entryLocal = entryDateTime.change(:offset => Time.current.localtime.strftime("%:z")) + entryTime = Time.parse("#{entryLocal.to_date.to_s} #{entryLocal.utc.to_time.to_s} ").localtime + end entryTime end diff --git a/app/views/wkattendance/clockedit.html.erb b/app/views/wkattendance/clockedit.html.erb index 419590579..32fc86ad6 100644 --- a/app/views/wkattendance/clockedit.html.erb +++ b/app/views/wkattendance/clockedit.html.erb @@ -59,7 +59,7 @@ <%=h hidden_field_tag("attnEntriesId#{j}", (entry_id.blank? ? "" : entry_id[j]) ) %> - @@ -69,9 +69,9 @@ <% end %> " > - - + +
<%=h text_field_tag("attnstarttime#{j}", start_time.blank? ? "" : start_time[j] ,:onchange => "#{} ", :size => 10, :disabled => isAccountUser ? false : true, :required => true, :onchange => "validateHr(this,#{(j)}, ['attnstarttime#{j}', 'attnendtime#{j}', 'hoursdiff#{j}', #{true}]);") %> <%=h text_field_tag("attnendtime#{j}", end_time.blank? ? "" : end_time[j],:size => 10, :disabled => isAccountUser ? false : true, :required => true, :onchange => "validateHr(this,#{(j)}, ['attnstarttime#{j}', 'attnendtime#{j}', 'hoursdiff#{j}', #{true}]);") %> + <%=h text_field_tag("attnendtime#{j}", end_time.blank? ? "" : end_time[j],:size => 10, :disabled => isAccountUser ? false : true, :onchange => "validateHr(this,#{(j)}, ['attnstarttime#{j}', 'attnendtime#{j}', 'hoursdiff#{j}', #{true}]);") %> <%=h text_field_tag("hoursdiff#{j}", hours.blank? ? 0 : hours[j].to_f,:size => 10, :disabled => isAccountUser ? false : true, :required => true) %>
<%=h text_field_tag("tothours", totalhours.round(2),:size => 10, :disabled => isAccountUser ? false : true, :required => true) %> - <%=h text_field_tag("tothours", totalhours.round(2),:size => 10, :disabled => isAccountUser ? false : true, :required => true) %> +
diff --git a/app/views/wkreport/reportattn.html.erb b/app/views/wkreport/reportattn.html.erb index ecc2b8de0..cfa94978d 100644 --- a/app/views/wkreport/reportattn.html.erb +++ b/app/views/wkreport/reportattn.html.erb @@ -114,7 +114,7 @@ <%=h attn_entry %> <% end -%> <%=h "" %> -<%=h totalhours.to_s %> +<%=h (totalhours.round(2)).to_s %> <%=h "" %> <%if showSlno %> <%=h index+1 %> diff --git a/config/locales/de.yml b/config/locales/de.yml index 8d1e44217..9190a9615 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -180,7 +180,7 @@ de: label_wk_register_for_shops: REGISTER OF EMPLOYMENT FOR SHOPS AND ESTABLISHMENTS label_wk_name_address: Name and Address of the Establishment label_date_of_entry_into_service: Date of entry into service - label_hours_note: "Note: Please enter time in 24 hours format." + label_hours_note: "Note: Please enter time in 24 hours format(HH:MM)." label_no_leaves_configured : No leaves configured label_max_min_hours_day_msg : Min hours is greater than Max hours. diff --git a/config/locales/en.yml b/config/locales/en.yml index 8c5bb9a22..b81a9c780 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -181,7 +181,7 @@ en: label_wk_register_for_shops: REGISTER OF EMPLOYMENT FOR SHOPS AND ESTABLISHMENTS label_wk_name_address: Name and Address of the Establishment label_date_of_entry_into_service: Date of entry into service - label_hours_note: "Note: Please enter time in 24 hours format." + label_hours_note: "Note: Please enter time in 24 hours format(HH:MM)." label_no_leaves_configured : No leaves configured label_max_min_hours_day_msg : Min hours is greater than Max hours. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 50210b344..c81d6d108 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -181,7 +181,7 @@ fr: label_wk_register_for_shops: REGISTRE DES EMPLOYES POUR BOUTIQUES ET ETABLISSEMENTS label_wk_name_address: Nom et adresse de l'établissement label_date_of_entry_into_service: Date d'entrée dans le service - label_hours_note: "Note: Merci de renseigner le temps au format 24 heures." + label_hours_note: "Note: Merci de renseigner le temps au format(HH:MM) 24 heures." label_no_leaves_configured : Aucun congé n'est configuré label_max_min_hours_day_msg : Le minum d'heure est plus grand que le maximum diff --git a/config/locales/it.yml b/config/locales/it.yml index dc2382fc8..5a9ac4839 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -178,7 +178,7 @@ it: label_wk_register_for_shops: REGISTER OF EMPLOYMENT FOR SHOPS AND ESTABLISHMENTS label_wk_name_address: Name and Address of the Establishment label_date_of_entry_into_service: Date of entry into service - label_hours_note: "Note: Please enter time in 24 hours format." + label_hours_note: "Note: Please enter time in 24 hours format(HH:MM)." label_no_leaves_configured : No leaves configured label_max_min_hours_day_msg : Min hours is greater than Max hours. diff --git a/init.rb b/init.rb index 90ad8508e..55ebffc8b 100644 --- a/init.rb +++ b/init.rb @@ -176,7 +176,7 @@ def destroy name 'Time & Attendance' author 'Adhi Software Pvt Ltd' description 'This plugin is for entering Time & Attendance' - version '2.2.1' + version '2.3' url 'http://www.redmine.org/plugins/wk-time' author_url 'http://www.adhisoftware.co.in/' From e3d98965a4f38ba021146629199447b730b233ef Mon Sep 17 00:00:00 2001 From: Karthick Date: Tue, 16 Aug 2016 13:39:01 +0530 Subject: [PATCH 26/37] Neglate negative in difference of two datetime --- app/helpers/wkattendance_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/wkattendance_helper.rb b/app/helpers/wkattendance_helper.rb index 5acee5567..22482b737 100644 --- a/app/helpers/wkattendance_helper.rb +++ b/app/helpers/wkattendance_helper.rb @@ -137,7 +137,7 @@ def addNewAttendance(startEntry,endEntry,userId) def saveAttendance(attnObj, startTime, endTime, userId, hasStartEnd) wkattendance = nil - if(!attnObj.blank? && ((attnObj.end_time.blank? && ((startTime - attnObj.start_time.localtime)/3600) < 24 )|| hasStartEnd)) + if(!attnObj.blank? && ((attnObj.end_time.blank? && ((startTime - attnObj.start_time.localtime)/3600) < 24 && ((startTime - attnObj.start_time.localtime)/3600) > 0 )|| hasStartEnd)) if !hasStartEnd entrydate = attnObj.start_time start_local = entrydate.localtime From 75a7b8f80355118b6e6f3c728aeca96ca776b456 Mon Sep 17 00:00:00 2001 From: Karthick Date: Wed, 17 Aug 2016 14:04:12 +0530 Subject: [PATCH 27/37] Show error msg when fields in file not configured --- app/helpers/wkimportattendance_helper.rb | 143 ++++++++++++----------- config/locales/de.yml | 3 +- config/locales/en.yml | 3 +- config/locales/fr.yml | 3 +- config/locales/it.yml | 3 +- 5 files changed, 83 insertions(+), 72 deletions(-) diff --git a/app/helpers/wkimportattendance_helper.rb b/app/helpers/wkimportattendance_helper.rb index fb50dd9ef..df3a8f939 100644 --- a/app/helpers/wkimportattendance_helper.rb +++ b/app/helpers/wkimportattendance_helper.rb @@ -23,86 +23,93 @@ def importAttendance(file,isAuto) if !(csv.length > 0) @errorMsg = l('error_no_record_to_import') end - csv.each_with_index do |row,index| - # rowValueHash - Have the data of the current row - rowValueHash = Hash.new - columnArr.each_with_index do |col,i| - case col when "user_id" - rowValueHash["user_id"] = row[i] - when "start_time","end_time" - if row_date(row[i]).is_a?(DateTime) || (row[i].blank? && col == "end_time") - rowValueHash[col] = row_date(row[i]) + if columnArr.blank? || !(columnArr.length > 0) + @errorMsg = l('warning_fields_in_file_not_configured') + end + if @errorMsg.blank? + csv.each_with_index do |row,index| + # rowValueHash - Have the data of the current row + rowValueHash = Hash.new + columnArr.each_with_index do |col,i| + case col when "user_id" + rowValueHash["user_id"] = row[i] + when "start_time","end_time" + if row_date(row[i]).is_a?(DateTime) || (row[i].blank? && col == "end_time") + rowValueHash[col] = row_date(row[i]) + else + #isValid = false + @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + end + when "hours" + rowValueHash[col] = row[i].to_f else - #isValid = false - @errorHash[index+1] = col + " " + l('activerecord.errors.messages.invalid') + if index < 1 + cfId = col.to_i #userCFHash[col] + userIdCFHash = getUserIdCFHash(cfId) + end + if userIdCFHash[row[i]].blank? + @errorHash[index+1] = userCFHash[col.to_i] + " " + l('activerecord.errors.messages.invalid') + else + rowValueHash["user_id"] = userIdCFHash[row[i]] + end end - when "hours" - rowValueHash[col] = row[i].to_f - else - if index < 1 - cfId = col.to_i #userCFHash[col] - userIdCFHash = getUserIdCFHash(cfId) + end + # Check the row has any invalid entries and skip that row from import + if @errorHash[index+1].blank? + @importCount = @importCount + 1 + userId = rowValueHash["user_id"] #row[0].to_i + endEntry = nil + startEntry = getFormatedTimeEntry(rowValueHash["start_time"]) + if !rowValueHash["end_time"].blank? && (rowValueHash["end_time"] != rowValueHash["start_time"]) + endEntry = getFormatedTimeEntry(rowValueHash["end_time"]) end - if userIdCFHash[row[i]].blank? - @errorHash[index+1] = userCFHash[col.to_i] + " " + l('activerecord.errors.messages.invalid') + + if (columnArr.include? "end_time") && (columnArr.include? "start_time") + #Get the imported records for particular user and start_time + importedEntry = WkAttendance.where(:user_id => userId, :start_time => startEntry) + if importedEntry[0].blank? + # There is no records for the given user on the given start_time + # Insert a new record to the database + lastAttnEntriesHash[userId] = addNewAttendance(startEntry,endEntry,userId) + else + # Update the record with end Entry + if importedEntry[0].end_time.blank? && !endEntry.blank? + lastAttnEntriesHash[userId] = saveAttendance(importedEntry[0], startEntry, endEntry, userId, true) + end + end else - rowValueHash["user_id"] = userIdCFHash[row[i]] + # Get the imported records for particular user and entry_time + # Skip the records which is already inserted by check importedEntry[0].blank? + importedEntry = WkAttendance.where("user_id = ? AND (start_time = ? OR end_time = ?)", userId, startEntry, startEntry) + if importedEntry[0].blank? + lastAttnEntriesHash[userId] = saveAttendance(lastAttnEntriesHash[userId], startEntry, endEntry, userId, false) + end end end end - # Check the row has any invalid entries and skip that row from import - if @errorHash[index+1].blank? - @importCount = @importCount + 1 - userId = rowValueHash["user_id"] #row[0].to_i - endEntry = nil - startEntry = getFormatedTimeEntry(rowValueHash["start_time"]) - if !rowValueHash["end_time"].blank? && (rowValueHash["end_time"] != rowValueHash["start_time"]) - endEntry = getFormatedTimeEntry(rowValueHash["end_time"]) + Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") + Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") + if isAuto + Rails.logger.info("====== File Name = #{File.basename file}=========") + if @importCount > 0 + Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") end - - if (columnArr.include? "end_time") && (columnArr.include? "start_time") - #Get the imported records for particular user and start_time - importedEntry = WkAttendance.where(:user_id => userId, :start_time => startEntry) - if importedEntry[0].blank? - # There is no records for the given user on the given start_time - # Insert a new record to the database - lastAttnEntriesHash[userId] = addNewAttendance(startEntry,endEntry,userId) - else - # Update the record with end Entry - if importedEntry[0].end_time.blank? && !endEntry.blank? - lastAttnEntriesHash[userId] = saveAttendance(importedEntry[0], startEntry, endEntry, userId, true) - end + if !@errorHash.blank? && @errorHash.count > 0 + Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") + Rails.logger.info("===============================================================") + Rails.logger.info(" Row || Message ") + Rails.logger.info("===============================================================") + @errorHash.each do |item| + Rails.logger.info(" #{item[0]} || #{simple_format_without_paragraph item[1]}") + Rails.logger.info("---------------------------------------------------------------") end - else - # Get the imported records for particular user and entry_time - # Skip the records which is already inserted by check importedEntry[0].blank? - importedEntry = WkAttendance.where("user_id = ? AND (start_time = ? OR end_time = ?)", userId, startEntry, startEntry) - if importedEntry[0].blank? - lastAttnEntriesHash[userId] = saveAttendance(lastAttnEntriesHash[userId], startEntry, endEntry, userId, false) - end - end - end - end - Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") - Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") - if isAuto - Rails.logger.info("====== File Name = #{File.basename file}=========") - if @importCount > 0 - Rails.logger.info("==== #{l(:notice_import_finished, :count => @importCount)} ====") - end - if !@errorHash.blank? && @errorHash.count > 0 - Rails.logger.info("==== #{l(:notice_import_finished_with_errors, :count => @errorHash.count, :total => (@errorHash.count + @importCount))} ====") - Rails.logger.info("===============================================================") - Rails.logger.info(" Row || Message ") - Rails.logger.info("===============================================================") - @errorHash.each do |item| - Rails.logger.info(" #{item[0]} || #{simple_format_without_paragraph item[1]}") - Rails.logger.info("---------------------------------------------------------------") + Rails.logger.info("===============================================================") end - Rails.logger.info("===============================================================") end + return @errorHash.blank? || @errorHash.count < 0 + else + return false end - return @errorHash.blank? || @errorHash.count < 0 end def read_file(file) diff --git a/config/locales/de.yml b/config/locales/de.yml index 9190a9615..039dae350 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -210,4 +210,5 @@ de: label_available_fields: Available Fields label_fields_in_file: Fields in File label_import_file_headers: File Headers - error_no_record_to_import: No Record to Import \ No newline at end of file + error_no_record_to_import: No Record to Import + warning_fields_in_file_not_configured: Fields in file not configured in plugin attendance settings \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index b81a9c780..c11868b6d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -211,4 +211,5 @@ en: label_available_fields: Available Fields label_fields_in_file: Fields in File label_import_file_headers: File Headers - error_no_record_to_import: No Record to Import \ No newline at end of file + error_no_record_to_import: No Record to Import + warning_fields_in_file_not_configured: Fields in file not configured in plugin attendance settings \ No newline at end of file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index c81d6d108..039aa0c1f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -211,4 +211,5 @@ fr: label_available_fields: Available Fields label_fields_in_file: Fields in File label_import_file_headers: File Headers - error_no_record_to_import: No Record to Import \ No newline at end of file + error_no_record_to_import: No Record to Import + warning_fields_in_file_not_configured: Fields in file not configured in plugin attendance settings \ No newline at end of file diff --git a/config/locales/it.yml b/config/locales/it.yml index 5a9ac4839..b51e68285 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -208,4 +208,5 @@ it: label_available_fields: Available Fields label_fields_in_file: Fields in File label_import_file_headers: File Headers - error_no_record_to_import: No Record to Import \ No newline at end of file + error_no_record_to_import: No Record to Import + warning_fields_in_file_not_configured: Fields in file not configured in plugin attendance settings \ No newline at end of file From e087e3962505d4d146c41b4211faeb313bf4d0d1 Mon Sep 17 00:00:00 2001 From: Karthick Date: Wed, 17 Aug 2016 14:12:00 +0530 Subject: [PATCH 28/37] Show the error message in next line --- app/helpers/wkimportattendance_helper.rb | 4 ++-- app/views/wkimportattendance/show.html.erb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/wkimportattendance_helper.rb b/app/helpers/wkimportattendance_helper.rb index df3a8f939..8a0ef3519 100644 --- a/app/helpers/wkimportattendance_helper.rb +++ b/app/helpers/wkimportattendance_helper.rb @@ -21,10 +21,10 @@ def importAttendance(file,isAuto) end columnArr = Setting.plugin_redmine_wktime['wktime_fields_in_file'] if !(csv.length > 0) - @errorMsg = l('error_no_record_to_import') + @errorMsg = @errorMsg.blank? ? l('error_no_record_to_import') : @errorMsg.to_s + "
" + l('error_no_record_to_import') end if columnArr.blank? || !(columnArr.length > 0) - @errorMsg = l('warning_fields_in_file_not_configured') + @errorMsg = @errorMsg.blank? ? l('warning_fields_in_file_not_configured') : @errorMsg.to_s + "
" + l('warning_fields_in_file_not_configured') end if @errorMsg.blank? csv.each_with_index do |row,index| diff --git a/app/views/wkimportattendance/show.html.erb b/app/views/wkimportattendance/show.html.erb index 21fa15a0e..0a2d83d9d 100644 --- a/app/views/wkimportattendance/show.html.erb +++ b/app/views/wkimportattendance/show.html.erb @@ -25,5 +25,5 @@ <% end %> <% else %> -

<%= @errorMsg %>

+

<%= @errorMsg.html_safe %>

<% end %> \ No newline at end of file From 23ef377e4d0ffd9c71bdc467b3a2eb99cf07e7db Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 18 Aug 2016 12:04:34 +0530 Subject: [PATCH 29/37] Fix for Date picker issue in redmine 3.3.0 --- app/views/settings/_tab_holidays.html.erb | 2 +- app/views/wktime/_te_new.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/settings/_tab_holidays.html.erb b/app/views/settings/_tab_holidays.html.erb index 52d7750b0..7dc7590c4 100644 --- a/app/views/settings/_tab_holidays.html.erb +++ b/app/views/settings/_tab_holidays.html.erb @@ -19,7 +19,7 @@ selectListAlertMsg = "<%=l(:label_wk_select_holiday) %>";

- <%= text_field_tag('holiday_date',Date.today.to_s,:size => 15, :required => true, :maxlength => 15) %><%= calendar_for('holiday_date') %> + <%= date_field_tag('holiday_date',Date.today.to_s,:size => 15, :required => true, :maxlength => 15) %><%= calendar_for('holiday_date') %>

<%= text_field_tag('holiday_desc','',:size => 20, :maxlength => 200) %> diff --git a/app/views/wktime/_te_new.html.erb b/app/views/wktime/_te_new.html.erb index 526c0d3ad..07901bb60 100644 --- a/app/views/wktime/_te_new.html.erb +++ b/app/views/wktime/_te_new.html.erb @@ -43,7 +43,7 @@ <% end %> <%=l(:field_start_date)%> -<%=h text_field_tag('startday',@startday,:size => 10, :required => true) %><%= calendar_for('startday') %> +<%=h date_field_tag('startday',@startday,:size => 10, :required => true) %><%= calendar_for('startday') %> From 849df09e6d4a41459e73dc22ef4fdef3a93340ce Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Thu, 18 Aug 2016 14:10:27 +0530 Subject: [PATCH 30/37] Bug fixing: clock in out list show only time --- app/views/wkattendance/_clk_list.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/wkattendance/_clk_list.html.erb b/app/views/wkattendance/_clk_list.html.erb index 58548672a..c747a97d8 100644 --- a/app/views/wkattendance/_clk_list.html.erb +++ b/app/views/wkattendance/_clk_list.html.erb @@ -18,8 +18,8 @@ <%= !entry.start_time ? "user locked" : "" %>" > <%=h entry.firstname %> <%=h entry.entry_date %> -<%=h !entry.start_time ? "" : entry.start_time.localtime.strftime('%r') %> -<%=h !entry.end_time ? "" : entry.end_time.localtime.strftime('%r') %> +<%=h !entry.start_time ? "" : entry.start_time.localtime.strftime('%R') %> +<%=h !entry.end_time ? "" : entry.end_time.localtime.strftime('%R') %> <%=h !entry.hours ? "" : (entry.hours).round(2) %> <%= link_to image_tag('edit.png'), {:controller => controller.controller_name, :action => 'clockedit', :user_id => entry.user_id, :date => entry.entry_date, :tab => controller.controller_name}, From 3cc7c5d57853022564903362760e41b0f1a6d055 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Thu, 18 Aug 2016 15:24:55 +0530 Subject: [PATCH 31/37] Bug Fixing: show import attendance link for TE Admin --- app/views/wkattendance/_clk_index.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/wkattendance/_clk_index.html.erb b/app/views/wkattendance/_clk_index.html.erb index fbe3569ad..6db984d92 100644 --- a/app/views/wkattendance/_clk_index.html.erb +++ b/app/views/wkattendance/_clk_index.html.erb @@ -7,9 +7,11 @@ //getMembersbyGroup <%= hidden_field_tag 'back_url', url_for(params) %> +<% if isAccountUser %>

<%= link_to l(:"label_import_attendance"), url_for(:controller => "wkimportattendance", :action => 'new', :tab => controller.controller_name)%>
+<% end %> <% wktime_helper = Object.new.extend(WktimeHelper) %> <%= form_tag({:controller => controller_name, :action => 'clockindex'}, :method => :get, :id => 'query_form') do %> <%=h hidden_field_tag('tab', "clock") %> @@ -17,7 +19,7 @@ <% groupid =session[:wkattendance][:group_id] userid =session[:wkattendance][:user_id] %> - <% if User.current.admin? || isAccountUser %> + <% if isAccountUser %> <% if !@groups.blank? %> From 11f3bf3891d3e16dd7baf682bab41922edb110e4 Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 18 Aug 2016 15:26:17 +0530 Subject: [PATCH 32/37] Modify label_wk_warning_nonsub_notification in language files --- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/it.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 039dae350..ac0d2f60a 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -71,7 +71,7 @@ de: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_wk_warning_nonsub_notification: "Note: Any change to the below settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" label_wk_minutes: Minuten label_wkexpense_entry_projects: Restrict Expense Entry to these projects diff --git a/config/locales/en.yml b/config/locales/en.yml index c11868b6d..59999aceb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -70,7 +70,7 @@ en: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_redmine_restart_warning: "Note: Any change to the below settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Restrict Expense Entry to these projects diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 039aa0c1f..e9ae4c7b3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -72,7 +72,7 @@ fr: label_wk_nonsub_mail_subject: Notification de retard label_wk_nonsub_mail_notification: Envoyer un courriel pour les retards label_wk_nonsub_mail_message: Corps du courriel de retard - label_redmine_restart_warning: "Note: une modification des paramètres de configuration sous-jacents demandera un redémarrage de Redmine" + label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Limiter la saisie de dépense à ces projets diff --git a/config/locales/it.yml b/config/locales/it.yml index b51e68285..ad982c015 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -72,7 +72,7 @@ it: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_redmine_restart_warning: "Note: Any change to the below settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Restrict Expense Entry to these projects From b7ba5c84da94f7288f3a3f711cd06eea677b8fd3 Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 18 Aug 2016 16:44:22 +0530 Subject: [PATCH 33/37] Typo in language files --- config/locales/de.yml | 2 +- config/locales/en.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/it.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index ac0d2f60a..a9c63d7dd 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -71,7 +71,7 @@ de: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below scheduler settings require redmine restart" label_wk_minutes: Minuten label_wkexpense_entry_projects: Restrict Expense Entry to these projects diff --git a/config/locales/en.yml b/config/locales/en.yml index 59999aceb..05f224161 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -70,7 +70,7 @@ en: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below scheduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Restrict Expense Entry to these projects diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e9ae4c7b3..1f125962f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -72,7 +72,7 @@ fr: label_wk_nonsub_mail_subject: Notification de retard label_wk_nonsub_mail_notification: Envoyer un courriel pour les retards label_wk_nonsub_mail_message: Corps du courriel de retard - label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below scheduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Limiter la saisie de dépense à ces projets diff --git a/config/locales/it.yml b/config/locales/it.yml index ad982c015..66b8520b9 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -72,7 +72,7 @@ it: label_wk_nonsub_mail_subject: Non submission time notification label_wk_nonsub_mail_notification: Send email for non submission label_wk_nonsub_mail_message: Non submission email message - label_redmine_restart_warning: "Note: Any change to the below schduler settings require redmine restart" + label_redmine_restart_warning: "Note: Any change to the below scheduler settings require redmine restart" label_wk_minutes: Minutes label_wkexpense_entry_projects: Restrict Expense Entry to these projects From 3762ad2655683c308882b2f1237a08f0e451c613 Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 18 Aug 2016 18:18:17 +0530 Subject: [PATCH 34/37] Add txt to import file lable --- app/views/wkimportattendance/new.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/wkimportattendance/new.html.erb b/app/views/wkimportattendance/new.html.erb index ef7da8ef9..4dc1911db 100644 --- a/app/views/wkimportattendance/new.html.erb +++ b/app/views/wkimportattendance/new.html.erb @@ -2,7 +2,7 @@ <%= form_tag wk_attendances_path, multipart: true do %>
- <%= l(:label_select_file_to_import) %> (CSV) + <%= l(:label_select_file_to_import) %> (CSV, txt)

<%= file_field_tag 'file' %>

From 2f91406d152ab0d1a9f79c1630f90a1eda2c613d Mon Sep 17 00:00:00 2001 From: Karthick Date: Thu, 18 Aug 2016 18:39:24 +0530 Subject: [PATCH 35/37] Page Error When there is no file selected --- .../wkimportattendance_controller.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/controllers/wkimportattendance_controller.rb b/app/controllers/wkimportattendance_controller.rb index 0a83089ac..2ba104c75 100644 --- a/app/controllers/wkimportattendance_controller.rb +++ b/app/controllers/wkimportattendance_controller.rb @@ -11,13 +11,17 @@ def new def show file = params[:file] - filePath = file.path - begin - isSuccess = importAttendance(filePath, false) - #redirect_to :action => 'show' - rescue Exception => e - @errorMsg = "Import failed: #{e.message}" - flash[:error] = @errorMsg + unless file.blank? + filePath = file.path + begin + isSuccess = importAttendance(filePath, false) + #redirect_to :action => 'show' + rescue Exception => e + @errorMsg = "Import failed: #{e.message}" + flash[:error] = @errorMsg + redirect_to :action => 'new' + end + else redirect_to :action => 'new' end end From cf61223e94e7c5d65796e9f436389be3f7185934 Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Thu, 18 Aug 2016 19:18:25 +0530 Subject: [PATCH 36/37] Bug Fixing: sqllite issue in expense --- app/controllers/wkexpense_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/wkexpense_controller.rb b/app/controllers/wkexpense_controller.rb index ae8059caa..e836eab2e 100644 --- a/app/controllers/wkexpense_controller.rb +++ b/app/controllers/wkexpense_controller.rb @@ -183,7 +183,7 @@ def getQuery(teQuery, ids, from, to, status) spField = getSpecificField() dtRangeForUsrSqlStr = "(" + getAllWeekSql(from, to) + ") tmp1" teSqlStr = "(" + teQuery + ") tmp2" - query = "select tmp3.user_id, tmp3.spent_on, tmp3.#{spField}, tmp3.status, tmp3.status_updater, tmp3.created_on, tmp3.currency from (select tmp1.id as user_id, tmp1.created_on, tmp1.selected_date as spent_on, " + + query = "select tmp3.user_id as user_id , tmp3.spent_on as spent_on, tmp3.#{spField} as #{spField}, tmp3.status as status, tmp3.status_updater as status_updater, tmp3.created_on as created_on, tmp3.currency as currency from (select tmp1.id as user_id, tmp1.created_on, tmp1.selected_date as spent_on, " + "case when tmp2.#{spField} is null then 0 else tmp2.#{spField} end as #{spField}, " + "case when tmp2.status is null then 'e' else tmp2.status end as status, tmp2.currency, tmp2.status_updater from " query = query + dtRangeForUsrSqlStr + " left join " + teSqlStr @@ -206,7 +206,7 @@ def findBySql(query) end def getTEAllTimeRange(ids) - teQuery = "select v.startday from (select #{getDateSqlString('t.spent_on')} as startday " + + teQuery = "select v.startday as startday from (select #{getDateSqlString('t.spent_on')} as startday " + "from wk_expense_entries t where user_id in (#{ids})) v group by v.startday order by v.startday" teResult = WkExpenseEntry.find_by_sql(teQuery) end From 60583042a7d81106ae21cc2a34dc56b6dcb1ca0a Mon Sep 17 00:00:00 2001 From: dhineshrajasekar Date: Fri, 19 Aug 2016 10:39:41 +0530 Subject: [PATCH 37/37] Update readme doc --- README.rdoc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.rdoc b/README.rdoc index 5d08eef78..c5b369b56 100644 --- a/README.rdoc +++ b/README.rdoc @@ -77,17 +77,17 @@ If an apache passenger module is used then make sure the following settings are b) RailsAppSpawnerIdleTime 0 c) PassengerPreStart http://rails-app-url/ -Release Notes for 2.2.1 +Release Notes for 2.3 Features: - Made compatible with Redmine 3.3.0. - - Time & Expense report in Report module. - - Show the first clock in and last clock out of the day. - - Show the List page for view permission holder also. + - File Based Integration with Attendance / Time Clock Device. + - Manually import Attendance data. + - clock in/out list and edit pages are avialable from Attendance module. + - Manually re-run the period end process for attendance module. Bugs: - - Fixed the clock in/out column shift error. - - Fixed the leave total hours bug in attendance list. - - Added permission logic for viewing expenses report. - - Left align the report header. + - Fixed the total hours for month column total in Attendance report. + - Fixed Date range calendar popup problem in Time & Attendance module. + - Fixed the sqlite query problem on the T&E list page. Customization: For any Customization/Support, please contact us, our consulting team will be happy to help you @@ -116,3 +116,5 @@ Resources: https://www.youtube.com/watch?v=BptCOCWgivY https://www.youtube.com/watch?v=afdVgCj-TUc https://www.youtube.com/watch?v=cTZ2FCqgdwQ + https://www.youtube.com/watch?v=RFlYw-ZpiYI + https://www.youtube.com/watch?v=RecxTps_jws
<%=l(:label_group_plural)%>