Index: app/helpers/application_helper.rb ======================================================================== --- app/helpers/application_helper.rb Fri May 31 10:36:41 2013 +0200 +++ app/helpers/application_helper.rb Fri May 31 17:49:32 2013 +0200 @@ -298,6 +298,28 @@ end end + def time_select_tag( name, stime ) + out = '' + time = stime.to_time(:utc) + if time.nil? + time = Date.today.to_time(:local) + end + time = time.in_time_zone(Time.zone.name) + out << select_tag( + "#{name}[hour]", + options_for_select( (0..23).map{|i| [i,i] }, time.hour ), + :style => 'min-width: 10px;max-width: 50px;' + ) + out << ':' + out << select_tag( + "#{name}[minute]", + options_for_select( (0..11).map{|i| [i*5,i*5] }, (time.min/5).round*5 ), + :style => 'min-width: 10px;max-width: 50px;' + ) + out << 'h' + out + end + def project_tree_options_for_select(projects, options = {}) s = '' project_tree(projects) do |project, level| Index: app/helpers/queries_helper.rb ======================================================================== --- app/helpers/queries_helper.rb Fri May 31 10:36:41 2013 +0200 +++ app/helpers/queries_helper.rb Fri May 31 17:49:32 2013 +0200 @@ -100,7 +100,12 @@ h(value) end when 'Time' - format_time(value) + if ( column.name == :start_date or column.name == :due_date ) and + ( !issue.project.use_datetime_for_issues or value.strftime('%H%M')=='0000' ) + format_date(value) + else + format_time(value) + end when 'Date' format_date(value) when 'Fixnum' Index: app/models/issue.rb ======================================================================== --- app/models/issue.rb Fri May 31 10:36:41 2013 +0200 +++ app/models/issue.rb Fri May 31 17:49:32 2013 +0200 @@ -61,6 +61,9 @@ DONE_RATIO_OPTIONS = %w(issue_field issue_status) attr_reader :current_journal + attr_accessor :start_time + attr_accessor :due_time + delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true validates_presence_of :subject, :priority, :project, :tracker, :author, :status @@ -68,8 +71,8 @@ validates_length_of :subject, :maximum => 255 validates_inclusion_of :done_ratio, :in => 0..100 validates :estimated_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} - validates :start_date, :date => true - validates :due_date, :date => true + #validates :start_date, :date => true + #validates :due_date, :date => true validate :validate_issue, :validate_required_fields scope :visible, lambda {|*args| @@ -90,8 +93,8 @@ ids.any? ? where(:fixed_version_id => ids) : where('1=0') } - before_create :default_assign - before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on + before_create :default_assign, :add_start_and_due_time + before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on, :add_start_and_due_time after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?} after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal # Should be after_create but would be called before previous after_save callbacks @@ -361,7 +364,9 @@ 'subject', 'description', 'start_date', + 'start_time', 'due_date', + 'due_time', 'done_ratio', 'estimated_hours', 'custom_field_values', @@ -1302,6 +1307,22 @@ end end + # Callback on start and due time + def add_start_and_due_time + if project.use_datetime_for_issues + if st=start_time and sd=start_date + if st['hour'].to_i >= 0 or st['minute'].to_i >= 0 + self.start_date = Time.parse( "#{sd.year}.#{sd.month}.#{sd.day} #{st['hour']}:#{st['minute']}:00" ) + end + end + if dt=due_time and dd=due_date + if dt['hour'].to_i >= 0 or dt['minute'].to_i >= 0 + self.due_date = Time.parse( "#{dd.year}.#{dd.month}.#{dd.day} #{dt['hour']}:#{dt['minute']}:00" ) + end + end + end + end + # Default assignment based on category def default_assign if assigned_to.nil? && category && category.assigned_to Index: app/models/project.rb ======================================================================== --- app/models/project.rb Fri May 31 10:36:41 2013 +0200 +++ app/models/project.rb Fri May 31 17:49:32 2013 +0200 @@ -650,6 +650,7 @@ 'description', 'homepage', 'is_public', + 'use_datetime_for_issues', 'identifier', 'custom_field_values', 'custom_fields', Index: app/views/issues/_attributes.html.erb ======================================================================== --- app/views/issues/_attributes.html.erb Fri May 31 10:36:41 2013 +0200 +++ app/views/issues/_attributes.html.erb Fri May 31 17:49:32 2013 +0200 @@ -47,11 +47,18 @@ <% end %> <% if @issue.safe_attribute? 'start_date' %> -

<%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('start_date') %><%= calendar_for('issue_start_date') if @issue.leaf? %>

+

+ <%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('start_date') %> + <%= calendar_for('issue_start_date') if @issue.leaf? %>
+ <%== time_select_tag( "issue[start_time]", format_time(@issue.start_date).to_s ) if @project.use_datetime_for_issues %> +

<% end %> <% if @issue.safe_attribute? 'due_date' %> -

<%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('due_date') %><%= calendar_for('issue_due_date') if @issue.leaf? %>

+

<%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('due_date') %> + <%= calendar_for('issue_due_date') if @issue.leaf? %>
+ <%== time_select_tag( "issue[due_time]", format_time(@issue.due_date).to_s ) if @project.use_datetime_for_issues %> +

<% end %> <% if @issue.safe_attribute? 'estimated_hours' %> Index: app/views/issues/show.html.erb ======================================================================== --- app/views/issues/show.html.erb Fri May 31 10:36:41 2013 +0200 +++ app/views/issues/show.html.erb Fri May 31 17:49:32 2013 +0200 @@ -47,10 +47,10 @@ end unless @issue.disabled_core_fields.include?('start_date') - rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' + rows.right l(:field_start_date), (@project.use_datetime_for_issues ? format_time(@issue.start_date) : format_date(@issue.start_date)), :class => 'start-date' end unless @issue.disabled_core_fields.include?('due_date') - rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' + rows.right l(:field_due_date), (@project.use_datetime_for_issues ? format_time(@issue.due_date) : format_date(@issue.due_date)), :class => 'due-date' end unless @issue.disabled_core_fields.include?('done_ratio') rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' Index: app/views/projects/_form.html.erb ======================================================================== --- app/views/projects/_form.html.erb Fri May 31 10:36:41 2013 +0200 +++ app/views/projects/_form.html.erb Fri May 31 17:49:32 2013 +0200 @@ -11,6 +11,7 @@ <% end %>

<%= f.text_field :homepage, :size => 60 %>

<%= f.check_box :is_public %>

+

<%= f.check_box :use_datetime_for_issues %>

<% unless @project.allowed_parents.compact.empty? %>

<%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>

Index: config/locales/cs.yml ======================================================================== --- config/locales/cs.yml Fri May 31 10:36:41 2013 +0200 +++ config/locales/cs.yml Fri May 31 17:49:32 2013 +0200 @@ -311,7 +311,7 @@ field_assigned_to_role: Role přiřaditele field_text: Textové pole field_visible: Viditelný - + field_use_datetime_for_issues: Použít u tiketů také čas setting_app_title: Název aplikace setting_app_subtitle: Podtitulek aplikace setting_welcome_text: Uvítací text Index: config/locales/en-GB.yml ======================================================================== --- config/locales/en-GB.yml Fri May 31 10:36:41 2013 +0200 +++ config/locales/en-GB.yml Fri May 31 17:49:32 2013 +0200 @@ -311,6 +311,7 @@ field_assigned_to_role: "Assignee's role" field_text: Text field field_visible: Visible + field_use_datetime_for_issues: Use time in tickets too field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" setting_app_title: Application title Index: config/locales/es.yml ======================================================================== --- config/locales/es.yml Fri May 31 10:36:41 2013 +0200 +++ config/locales/es.yml Fri May 31 17:49:32 2013 +0200 @@ -1108,6 +1108,7 @@ button_hide: Ocultar setting_non_working_week_days: Días no laborables label_in_the_next_days: en los próximos + field_use_datetime_for_issues: Usar hora en prog peticiones label_in_the_past_days: en los anteriores label_attribute_of_user: "%{name} del usuario" text_turning_multiple_off: Si desactiva los valores múltiples, éstos serán eliminados para dejar un único valor por elemento. Index: config/locales/en.yml ======================================================================== --- config/locales/en.yml Fri May 31 10:36:41 2013 +0200 +++ config/locales/en.yml Fri May 31 17:49:32 2013 +0200 @@ -314,6 +314,7 @@ field_assigned_to_role: "Assignee's role" field_text: Text field field_visible: Visible + field_use_datetime_for_issues: Use time in tickets too field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" field_issues_visibility: Issues visibility field_is_private: Private Index: db/migrate/20130531174459_add_time_to_issue_start_date_and_issue_due_date.rb ======================================================================== --- db/migrate/20130531174459_add_time_to_issue_start_date_and_issue_due_date.rb Thu Jan 01 00:00:00 1970 +0000 +++ db/migrate/20130531174459_add_time_to_issue_start_date_and_issue_due_date.rb Fri May 31 17:49:32 2013 +0200 @@ -0,0 +1,11 @@ +class AddTimeToIssueStartDateAndIssueDueDate < ActiveRecord::Migration + def self.up + change_column :issues, :start_date, :datetime + change_column :issues, :due_date, :datetime + end + + def self.down + change_column :issues, :start_date, :date + change_column :issues, :due_date, :date + end +end Index: db/migrate/20130531174549_add_use_datetime_for_issues_to_projects.rb ======================================================================== --- db/migrate/20130531174549_add_use_datetime_for_issues_to_projects.rb Thu Jan 01 00:00:00 1970 +0000 +++ db/migrate/20130531174549_add_use_datetime_for_issues_to_projects.rb Fri May 31 17:49:32 2013 +0200 @@ -0,0 +1,11 @@ +class AddUseDatetimeForIssuesToProjects < ActiveRecord::Migration + + def self.up + add_column :projects, :use_datetime_for_issues, :boolean, :default => false + end + + def self.down + remove_column :projects, :use_datetime_for_issues + end + +end Index: lib/redmine/utils.rb ======================================================================== --- lib/redmine/utils.rb Sun Apr 21 09:00:27 2013 +0000 +++ lib/redmine/utils.rb Wed Jun 05 15:41:36 2013 +0200 @@ -60,7 +60,7 @@ weeks = days / 7 result = weeks * (7 - non_working_week_days.size) days_left = days - weeks * 7 - start_cwday = from.cwday + start_cwday = from.to_date.cwday days_left.times do |i| unless non_working_week_days.include?(((start_cwday + i - 1) % 7) + 1) result += 1 @@ -78,7 +78,7 @@ weeks = working_days / (7 - non_working_week_days.size) result = weeks * 7 days_left = working_days - weeks * (7 - non_working_week_days.size) - cwday = date.cwday + cwday = date.to_date.cwday while days_left > 0 cwday += 1 unless non_working_week_days.include?(((cwday - 1) % 7) + 1) @@ -94,7 +94,7 @@ # Returns the date of the first day on or after the given date that is a working day def next_working_date(date) - cwday = date.cwday + cwday = date.to_date.cwday days = 0 while non_working_week_days.include?(((cwday + days - 1) % 7) + 1) days += 1