diff options
| author | Zog | 2018-01-24 16:56:16 +0100 |
|---|---|---|
| committer | Zog | 2018-01-31 15:14:00 +0100 |
| commit | 663effc415399c61d22dadbc235bb7488022d191 (patch) | |
| tree | cc943f110c9245575c75ebe6cac4b7bfd7152149 /app/models | |
| parent | b83d26389e6726eaea86955c3a2d2bffa5e65b5e (diff) | |
| download | chouette-core-663effc415399c61d22dadbc235bb7488022d191.tar.bz2 | |
Refs #5682 @3h; Use same UI as for timetables
Diffstat (limited to 'app/models')
| -rw-r--r-- | app/models/calendar.rb | 79 | ||||
| -rw-r--r-- | app/models/calendar/period.rb | 5 | ||||
| -rw-r--r-- | app/models/chouette/time_table.rb | 96 | ||||
| -rw-r--r-- | app/models/concerns/application_days_support.rb | 4 | ||||
| -rw-r--r-- | app/models/concerns/date_support.rb | 11 | ||||
| -rw-r--r-- | app/models/concerns/timetable_support.rb | 149 |
6 files changed, 271 insertions, 73 deletions
diff --git a/app/models/calendar.rb b/app/models/calendar.rb index a4d279e25..561a2e3f7 100644 --- a/app/models/calendar.rb +++ b/app/models/calendar.rb @@ -6,6 +6,7 @@ class Calendar < ActiveRecord::Base include DateSupport include PeriodSupport include ApplicationDaysSupport + include TimetableSupport has_paper_trail class_name: 'PublicVersion' belongs_to :organisation @@ -16,16 +17,29 @@ class Calendar < ActiveRecord::Base has_many :time_tables scope :contains_date, ->(date) { where('date ? = any (dates) OR date ? <@ any (date_ranges)', date, date) } - before_create :set_default_days + + after_initialize :set_defaults def self.ransackable_scopes(auth_object = nil) [:contains_date] end - def set_default_days + def self.state_permited_attributes item + {name: item["comment"]} + end + + def set_defaults + self.excluded_dates ||= [] self.int_day_types ||= EVERYDAY end + def human_attribute_name(*args) + self.class.human_attribute_name(*args) + end + + def shortcuts_update(date=nil) + end + def convert_to_time_table Chouette::TimeTable.new.tap do |tt| self.dates.each do |d| @@ -38,4 +52,65 @@ class Calendar < ActiveRecord::Base end end + def include_in_dates?(day) + self.dates.include? day + end + + def excluded_date?(day) + self.excluded_dates.include? day + end + + def update_in_out date, in_out + if in_out + self.excluded_dates.delete date + self.dates << date unless include_in_dates?(date) + else + self.dates.delete date + self.excluded_dates << date unless excluded_date?(date) + end + date + end + + def included_days + dates + end + + def excluded_days + excluded_dates + end + + def saved_dates + Hash[*self.dates.each_with_index.to_a.map(&:reverse).flatten] + end + + def all_dates + (dates + excluded_dates).sort.each_with_index.map do |d, i| + OpenStruct.new(id: i, date: d, in_out: include_in_dates?(d)) + end + end + + def find_date_by_id id + self.dates[id] + end + + def destroy_date date + self.dates -= [date] + end + + def create_date in_out:, date: + update_in_out date, in_out + end + + def find_period_by_id id + self.periods.find{|p| p.id == id} + end + + def build_period + self.periods << Calendar::Period.new(id: self.periods.count + 1) + self.periods.last + end + + def destroy_period period + @periods = self.periods.select{|p| p.end != period.end || p.begin != period.begin} + end end diff --git a/app/models/calendar/period.rb b/app/models/calendar/period.rb index 56ab722fe..8b3e4109b 100644 --- a/app/models/calendar/period.rb +++ b/app/models/calendar/period.rb @@ -10,6 +10,11 @@ class Calendar < ActiveRecord::Base validates_presence_of :begin, :end validate :check_end_greather_than_begin + alias_method :period_start, :begin + alias_method :period_end, :end + alias_method :period_start=, :begin= + alias_method :period_end=, :end= + def check_end_greather_than_begin if self.begin && self.end && self.begin >= self.end errors.add(:base, I18n.t('calendars.errors.short_period')) diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb index 1a1972113..8113457ec 100644 --- a/app/models/chouette/time_table.rb +++ b/app/models/chouette/time_table.rb @@ -5,6 +5,7 @@ module Chouette include TimeTableRestrictions include ObjectidSupport include ApplicationDaysSupport + include TimetableSupport # FIXME http://jira.codehaus.org/browse/JRUBY-6358 self.primary_key = "id" @@ -82,72 +83,36 @@ module Chouette end end - def state_update state - update_attributes(self.class.state_permited_attributes(state)) - self.tag_list = state['tags'].collect{|t| t['name']}.join(', ') - self.calendar_id = nil unless state['calendar'] - - days = state['day_types'].split(',') - Date::DAYNAMES.map(&:underscore).each do |name| - prefix = human_attribute_name(name).first(2) - send("#{name}=", days.include?(prefix)) - end - - saved_dates = Hash[self.dates.collect{ |d| [d.id, d.date]}] - cmonth = Date.parse(state['current_periode_range']) - - state['current_month'].each do |d| - date = Date.parse(d['date']) - checked = d['include_date'] || d['excluded_date'] - in_out = d['include_date'] ? true : false - - date_id = saved_dates.key(date) - time_table_date = self.dates.find(date_id) if date_id + def find_date_by_id id + self.dates.find id + end - next if !checked && !time_table_date - # Destroy date if no longer checked - next if !checked && time_table_date.destroy + def destroy_date date + date.destroy + end - # Create new date - unless time_table_date - time_table_date = self.dates.create({in_out: in_out, date: date}) - end - # Update in_out - if in_out != time_table_date.in_out - time_table_date.update_attributes({in_out: in_out}) - end + def update_in_out date, in_out + if in_out != date.in_out + date.update_attributes({in_out: in_out}) end - - self.state_update_periods state['time_table_periods'] - self.save end - def state_update_periods state_periods - state_periods.each do |item| - period = self.periods.find(item['id']) if item['id'] - next if period && item['deleted'] && period.destroy - period ||= self.periods.build - - period.period_start = Date.parse(item['period_start']) - period.period_end = Date.parse(item['period_end']) + def find_period_by_id id + self.periods.find id + end - if period.changed? - period.save - item['id'] = period.id - end - end + def build_period + periods.build + end - state_periods.delete_if {|item| item['deleted']} + def destroy_period period + period.destroy end def self.state_permited_attributes item item.slice('comment', 'color').to_hash end - def presenter - @presenter ||= ::TimeTablePresenter.new( self) - end - def self.start_validity_period [Chouette::TimeTable.minimum(:start_date)].compact.min end @@ -168,20 +133,6 @@ module Chouette self.save end - def month_inspect(date) - (date.beginning_of_month..date.end_of_month).map do |d| - { - day: I18n.l(d, format: '%A'), - date: d.to_s, - wday: d.wday, - wnumber: d.strftime("%W").to_s, - mday: d.mday, - include_date: include_in_dates?(d), - excluded_date: excluded_date?(d) - } - end - end - def save_shortcuts shortcuts_update self.update_column(:start_date, start_date) @@ -361,6 +312,17 @@ module Chouette days.sort end + def create_date in_out:, date: + self.dates.create in_out: in_out, date: date + end + + def saved_dates + Hash[self.dates.collect{ |d| [d.id, d.date]}] + end + + def all_dates + dates + end # produce a copy of periods without anyone overlapping or including another def optimize_overlapping_periods diff --git a/app/models/concerns/application_days_support.rb b/app/models/concerns/application_days_support.rb index 425cba5bf..348436aa4 100644 --- a/app/models/concerns/application_days_support.rb +++ b/app/models/concerns/application_days_support.rb @@ -35,6 +35,10 @@ module ApplicationDaysSupport end end + def valid_day? wday + valid_days.include?(wday) + end + def self.valid_days(int_day_types) # Build an array with day of calendar week (1-7, Monday is 1). [].tap do |valid_days| diff --git a/app/models/concerns/date_support.rb b/app/models/concerns/date_support.rb index fbfe19af1..5c66cb1a9 100644 --- a/app/models/concerns/date_support.rb +++ b/app/models/concerns/date_support.rb @@ -38,9 +38,12 @@ module DateSupport date_values_are_valid = false end date_ranges.each do |date_range| - if date_range.cover? date_value.value - date_value.errors.add(:base, I18n.t('activerecord.errors.models.calendar.attributes.dates.date_in_date_ranges')) - date_values_are_valid = false + if date_range.cover?(date_value.value) + excluded_day = self.respond_to?(:valid_day?) && !self.valid_day?(date_value.value.wday) + unless excluded_day + date_value.errors.add(:base, I18n.t('activerecord.errors.models.calendar.attributes.dates.date_in_date_ranges')) + date_values_are_valid = false + end end end end @@ -77,4 +80,4 @@ module DateSupport private :clear_date_values end -end
\ No newline at end of file +end diff --git a/app/models/concerns/timetable_support.rb b/app/models/concerns/timetable_support.rb new file mode 100644 index 000000000..8c49723fe --- /dev/null +++ b/app/models/concerns/timetable_support.rb @@ -0,0 +1,149 @@ +module TimetableSupport + extend ActiveSupport::Concern + + def presenter + @presenter ||= ::TimeTablePresenter.new( self) + end + + def periods_max_date + return nil if self.periods.empty? + + min_start = self.periods.map(&:period_start).compact.min + max_end = self.periods.map(&:period_end).compact.max + result = nil + + if max_end && min_start + max_end.downto( min_start) do |date| + if self.valid_days.include?(date.cwday) && !self.excluded_date?(date) + result = date + break + end + end + end + result + end + + def periods_min_date + return nil if self.periods.empty? + + min_start = self.periods.map(&:period_start).compact.min + max_end = self.periods.map(&:period_end).compact.max + result = nil + + if max_end && min_start + min_start.upto(max_end) do |date| + if self.valid_days.include?(date.cwday) && !self.excluded_date?(date) + result = date + break + end + end + end + result + end + + def bounding_dates + bounding_min = self.all_dates.select{|d| d.in_out}.map(&:date).compact.min + bounding_max = self.all_dates.select{|d| d.in_out}.map(&:date).compact.max + + unless self.periods.empty? + bounding_min = periods_min_date if periods_min_date && + (bounding_min.nil? || (periods_min_date < bounding_min)) + + bounding_max = periods_max_date if periods_max_date && + (bounding_max.nil? || (bounding_max < periods_max_date)) + end + + [bounding_min, bounding_max].compact + end + + def month_inspect(date) + (date.beginning_of_month..date.end_of_month).map do |d| + { + day: I18n.l(d, format: '%A'), + date: d.to_s, + wday: d.wday, + wnumber: d.strftime("%W").to_s, + mday: d.mday, + include_date: include_in_dates?(d), + excluded_date: excluded_date?(d) + } + end + end + + def include_in_dates?(day) + self.dates.any?{ |d| d.date === day && d.in_out == true } + end + + def excluded_date?(day) + self.dates.any?{ |d| d.date === day && d.in_out == false } + end + + def include_in_overlap_dates?(day) + return false if self.excluded_date?(day) + + self.all_dates.any?{ |d| d.date === day} \ + && self.periods.any?{ |period| period.period_start <= day && day <= period.period_end && valid_days.include?(day.cwday) } + end + + def include_in_periods?(day) + self.periods.any?{ |period| period.period_start <= day && + day <= period.period_end && + valid_days.include?(day.cwday) && + ! excluded_date?(day) } + end + + def state_update_periods state_periods + state_periods.each do |item| + period = self.find_period_by_id(item['id']) if item['id'] + next if period && item['deleted'] && self.destroy_period(period) + period ||= self.build_period + + period.period_start = Date.parse(item['period_start']) + period.period_end = Date.parse(item['period_end']) + + period.save if period === ActiveRecord::Base && period.changed? + + item['id'] = period.id + end + + state_periods.delete_if {|item| item['deleted']} + end + + def state_update state + update_attributes(self.class.state_permited_attributes(state)) + self.tag_list = state['tags'].collect{|t| t['name']}.join(', ') if state['tags'] + self.calendar_id = nil if self.respond_to?(:calendar_id) && !state['calendar'] + + days = state['day_types'].split(',') + Date::DAYNAMES.map(&:underscore).each do |name| + prefix = human_attribute_name(name).first(2) + send("#{name}=", days.include?(prefix)) + end + + cmonth = Date.parse(state['current_periode_range']) + + state['current_month'].each do |d| + date = Date.parse(d['date']) + checked = d['include_date'] || d['excluded_date'] + in_out = d['include_date'] ? true : false + + date_id = saved_dates.key(date) + time_table_date = self.find_date_by_id(date_id) if date_id + + next if !checked && !time_table_date + # Destroy date if no longer checked + next if !checked && destroy_date(time_table_date) + + # Create new date + unless time_table_date + time_table_date = self.create_date in_out: in_out, date: date + end + # Update in_out + self.update_in_out time_table_date, in_out + end + + self.state_update_periods state['time_table_periods'] + self.save + end + +end |
