diff --git a/app/models/alma.rb b/app/models/alma.rb index 4028abb..a312270 100644 --- a/app/models/alma.rb +++ b/app/models/alma.rb @@ -9,8 +9,9 @@ class Alma attr_reader :date_to def initialize(args) - @date_from = args[:date_from] - @date_to = args[:date_to] + dates_input = add_extra_day(args[:date_from], args[:date_to]) + @date_from = dates_input.first + @date_to = dates_input.last @limited = args[:limited] @raw_hours = fetch_dates end @@ -21,6 +22,14 @@ def hours_json private + def add_extra_day(day_from, day_to) + # get next day date and add it to the end of the list (this is used in the + # parser to determine labels that change depending on future times + dates_new = [day_from, day_to].sort + dates_new << DateTime.parse(dates_new.last).next_day.strftime('%Y-%m-%d') + [dates_new.first, dates_new.last] + end + ## # Fetch the Alma Open Hours in json format for the givend dates # @return [Hash] raw hours from Alma diff --git a/app/services/api/library_open_hours_json.rb b/app/services/api/library_open_hours_json.rb index 5fa2da5..0eb6c75 100644 --- a/app/services/api/library_open_hours_json.rb +++ b/app/services/api/library_open_hours_json.rb @@ -17,9 +17,11 @@ def self.call(raw_hours, limited = false) def call hours_data = {} @raw_hours.each do |day, hour| - hours_data[day] = lib_open_hours(hour['day']) + next_day = @raw_hours[DateTime.parse(day).next_day.to_s] + hours_data[day] = lib_open_hours(hour['day'], next_day) end - hours_data.to_json + hours_data.without(hours_data.to_a.last.first).to_json + # hours_data.to_json end private @@ -29,7 +31,7 @@ def initialize(raw_hours, limited = false) @limited = limited end - def lib_open_hours(raw_json) + def lib_open_hours(raw_json, next_day_json) return {} if raw_json.blank? alma_day = raw_json.first @@ -42,8 +44,8 @@ def lib_open_hours(raw_json) close: to_hour.present? ? format_hour(to_hour) : '', string_date: alma_date.strftime('%a, %b %-d, %Y'), sortable_date: alma_date.strftime('%Y-%m-%d'), - formatted_hours: all_formatted_hours(alma_day, false), - formatted_hours_plain_text: all_formatted_hours(alma_day, true), + formatted_hours: all_formatted_hours(day: alma_day, next_day: next_day_json, plain_text: false), + formatted_hours_plain_text: all_formatted_hours(day: alma_day, next_day: next_day_json, plain_text: true), open_all_day: open_all_day?(from_hour, to_hour), closes_at_night: closes_at_night?(last_to_hour), event_desc: '', @@ -89,13 +91,14 @@ def event_status(day) all_open_hours(day).count.zero? ? 'CLOSE' : '' end - def all_formatted_hours(day, plain_text = false) + def all_formatted_hours(day:, next_day:, plain_text: false) return 'Closed' if all_open_hours(day).count.zero? return limited_formatted_hours(day, plain_text) if limited_hours?(day) + # byebug if day['date'] == '2020-03-13Z' all_open_hours(day).map do |h| - formatted_hours(h[:open], h[:close]) + formatted_hours(open_time: h[:open], close_time: h[:close], day: day, next_day: next_day) end.join(hours_delimiter(plain_text)) end @@ -141,11 +144,18 @@ def open_all_day?(open_time, close_time) open_time == '00:00' && close_time == '23:59' ? true : false end - def formatted_hours(open_time, close_time) - if close_time == '00:14' || partially_open?(open_time, close_time) + def formatted_hours(open_time:, close_time:, day:, next_day:) + # byebug if day['date'] == '2020-03-13Z' + if close_time == '00:14' + "#{format_hour(open_time)} - No closing" + elsif partially_open?(open_time, close_time) && close_midnight?(next_day) + "#{format_hour(open_time)} - midnight" + elsif partially_open?(open_time, close_time) "#{format_hour(open_time)} - No closing" elsif open_time == '00:14' "Closes at #{format_hour(close_time)}" + elsif open_time == '00:00' && close_time == '23:59' && close_midnight?(next_day) + "#{format_hour(open_time)} - midnight" elsif open_time == '00:00' && close_time == '23:59' 'Open 24 Hours' elsif open_time.eql? close_time @@ -155,6 +165,12 @@ def formatted_hours(open_time, close_time) end end + # check if a day is closing at midnight (next day doesn't open at 00:00) + def close_midnight?(next_day) + next_day_open_time = next_day.try(:[], 'day').try(:first).try(:[], 'hour').try(:first).try(:[], 'from') + next_day_open_time.present? ? next_day_open_time != '00:00' : false + end + def format_hour(time) Time.parse(time).strftime('%-l:%M%P') end diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb index a8c641f..2593e1a 100644 --- a/spec/controllers/api_controller_spec.rb +++ b/spec/controllers/api_controller_spec.rb @@ -32,10 +32,12 @@ end let(:alma_with_special_hours) { AlmaSpecialHours.new } let(:url) { "#{ENV['ALMA_OPEN_HOURS_URL']}?apikey=#{ENV['ALMA_API_KEY']}&from=#{date_from}&to=#{date_to}" } + let(:url_next) { "#{ENV['ALMA_OPEN_HOURS_URL']}?apikey=#{ENV['ALMA_API_KEY']}&from=#{next_day}&to=#{next_day}" } let(:open_and_special_hours_url) { "#{ENV['ALMA_SPECIAL_HOURS_URL']}?apikey=#{ENV['ALMA_API_KEY']}&scope=#{ENV['ALMA_SPECIAL_HOURS_SCOPE']}" } let(:xml) { File.read("spec/fixtures/alma_open_hours.xml") } let(:date_from) { '2019-06-24' } let(:date_to) { '2019-06-24' } + let(:next_day) { DateTime.parse(date_to).next_day.strftime('%Y-%m-%d') } let(:dates) { [date_from, date_to] } before do @@ -53,12 +55,23 @@ 'User-Agent'=>'Ruby' }). to_return(status: 200, body: raw_json, headers: {}) + + stub_request(:get, url_next). + with( + headers: { + 'Accept'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'User-Agent'=>'Ruby' + }). + to_return(status: 200, body: raw_json, headers: {}) end context "When no day is provided" do let(:day) { '' } let(:date_from) { day } let(:date_to) { day } + let(:next_day) { '' } + before do allow(API::OpenAndSpecialHoursXmlToJsonParser).to receive(:call).with(anything(), []).and_return(valid_json) diff --git a/spec/fixtures/alma_january_2020_raw.json b/spec/fixtures/alma_january_2020_raw.json index 6179ed2..f1b6a92 100644 --- a/spec/fixtures/alma_january_2020_raw.json +++ b/spec/fixtures/alma_january_2020_raw.json @@ -584,5 +584,7 @@ ] } ] + }, + "2020-02-01T00:00:00+00:00": { } } diff --git a/spec/fixtures/alma_june_2019_raw.json b/spec/fixtures/alma_june_2019_raw.json index f3c1127..72795ba 100644 --- a/spec/fixtures/alma_june_2019_raw.json +++ b/spec/fixtures/alma_june_2019_raw.json @@ -516,5 +516,8 @@ ] } ] + }, + "2019-07-01T00:00:00+00:00": { } + } diff --git a/spec/fixtures/alma_june_2020_raw.json b/spec/fixtures/alma_june_2020_raw.json index a337336..ff4d4ec 100644 --- a/spec/fixtures/alma_june_2020_raw.json +++ b/spec/fixtures/alma_june_2020_raw.json @@ -516,5 +516,7 @@ ] } ] + }, + "2020-07-01T00:00:00+00:00": { } } diff --git a/spec/fixtures/alma_march_2020.json b/spec/fixtures/alma_march_2020.json index 0124197..2004f8c 100644 --- a/spec/fixtures/alma_march_2020.json +++ b/spec/fixtures/alma_march_2020.json @@ -4,7 +4,8 @@ "close": "11:59pm", "string_date": "Sun, Mar 1, 2020", "sortable_date": "2020-03-01", - "formatted_hours": "10:00am - 12:00am", + "formatted_hours": "10:00am - No closing", + "formatted_hours_plain_text": "10:00am - No closing", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -21,7 +22,8 @@ "close": "2:00am", "string_date": "Mon, Mar 2, 2020", "sortable_date": "2020-03-02", - "formatted_hours": "12:00am - 2:00am
6:00am - 12:00am", + "formatted_hours": "Open 24 Hours
2:00am-6:00am Limited library services in Java II", + "formatted_hours_plain_text": "Open 24 Hours, 2:00am-6:00am Limited library services in Java II", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -42,7 +44,8 @@ "close": "2:00am", "string_date": "Tue, Mar 3, 2020", "sortable_date": "2020-03-03", - "formatted_hours": "12:00am - 2:00am
6:00am - 12:00am", + "formatted_hours": "Open 24 Hours
2:00am-6:00am Limited library services in Java II", + "formatted_hours_plain_text": "Open 24 Hours, 2:00am-6:00am Limited library services in Java II", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -63,7 +66,8 @@ "close": "2:00am", "string_date": "Wed, Mar 4, 2020", "sortable_date": "2020-03-04", - "formatted_hours": "12:00am - 2:00am
6:00am - 12:00am", + "formatted_hours": "Open 24 Hours
2:00am-6:00am Limited library services in Java II", + "formatted_hours_plain_text": "Open 24 Hours, 2:00am-6:00am Limited library services in Java II", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -84,7 +88,8 @@ "close": "2:00am", "string_date": "Thu, Mar 5, 2020", "sortable_date": "2020-03-05", - "formatted_hours": "12:00am - 2:00am
6:00am - 12:00am", + "formatted_hours": "Open 24 Hours
2:00am-6:00am Limited library services in Java II", + "formatted_hours_plain_text": "Open 24 Hours, 2:00am-6:00am Limited library services in Java II", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -105,7 +110,8 @@ "close": "2:00am", "string_date": "Fri, Mar 6, 2020", "sortable_date": "2020-03-06", - "formatted_hours": "12:00am - 2:00am
6:00am - 10:00pm", + "formatted_hours": "12:00am - 10:00pm
2:00am-6:00am Limited library services in Java II", + "formatted_hours_plain_text": "12:00am - 10:00pm, 2:00am-6:00am Limited library services in Java II", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -127,6 +133,7 @@ "string_date": "Sat, Mar 7, 2020", "sortable_date": "2020-03-07", "formatted_hours": "10:00am - 10:00pm", + "formatted_hours_plain_text": "10:00am - 10:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -143,7 +150,8 @@ "close": "11:59pm", "string_date": "Sun, Mar 8, 2020", "sortable_date": "2020-03-08", - "formatted_hours": "10:00am - 12:00am", + "formatted_hours": "10:00am - No closing", + "formatted_hours_plain_text": "10:00am - No closing", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -161,6 +169,7 @@ "string_date": "Mon, Mar 9, 2020", "sortable_date": "2020-03-09", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -178,6 +187,7 @@ "string_date": "Tue, Mar 10, 2020", "sortable_date": "2020-03-10", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -195,6 +205,7 @@ "string_date": "Wed, Mar 11, 2020", "sortable_date": "2020-03-11", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -212,6 +223,7 @@ "string_date": "Thu, Mar 12, 2020", "sortable_date": "2020-03-12", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -228,7 +240,8 @@ "close": "11:59pm", "string_date": "Fri, Mar 13, 2020", "sortable_date": "2020-03-13", - "formatted_hours": "Open 24 Hours", + "formatted_hours": "12:00am - midnight", + "formatted_hours_plain_text": "12:00am - midnight", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -245,7 +258,8 @@ "close": "11:59pm", "string_date": "Sat, Mar 14, 2020", "sortable_date": "2020-03-14", - "formatted_hours": "10:00am - 12:00am", + "formatted_hours": "10:00am - midnight", + "formatted_hours_plain_text": "10:00am - midnight", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -262,7 +276,8 @@ "close": "11:59pm", "string_date": "Sun, Mar 15, 2020", "sortable_date": "2020-03-15", - "formatted_hours": "10:00am - 12:00am", + "formatted_hours": "10:00am - No closing", + "formatted_hours_plain_text": "10:00am - No closing", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -280,6 +295,7 @@ "string_date": "Mon, Mar 16, 2020", "sortable_date": "2020-03-16", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -297,6 +313,7 @@ "string_date": "Tue, Mar 17, 2020", "sortable_date": "2020-03-17", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -314,6 +331,7 @@ "string_date": "Wed, Mar 18, 2020", "sortable_date": "2020-03-18", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -331,6 +349,7 @@ "string_date": "Thu, Mar 19, 2020", "sortable_date": "2020-03-19", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", @@ -348,6 +367,7 @@ "string_date": "Fri, Mar 20, 2020", "sortable_date": "2020-03-20", "formatted_hours": "12:00am - 6:00pm", + "formatted_hours_plain_text": "12:00am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -365,6 +385,7 @@ "string_date": "Sat, Mar 21, 2020", "sortable_date": "2020-03-21", "formatted_hours": "1:00pm - 6:00pm", + "formatted_hours_plain_text": "1:00pm - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -382,6 +403,7 @@ "string_date": "Sun, Mar 22, 2020", "sortable_date": "2020-03-22", "formatted_hours": "1:00pm - 6:00pm", + "formatted_hours_plain_text": "1:00pm - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -399,6 +421,7 @@ "string_date": "Mon, Mar 23, 2020", "sortable_date": "2020-03-23", "formatted_hours": "7:30am - 6:00pm", + "formatted_hours_plain_text": "7:30am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -416,6 +439,7 @@ "string_date": "Tue, Mar 24, 2020", "sortable_date": "2020-03-24", "formatted_hours": "7:30am - 6:00pm", + "formatted_hours_plain_text": "7:30am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -433,6 +457,7 @@ "string_date": "Wed, Mar 25, 2020", "sortable_date": "2020-03-25", "formatted_hours": "7:30am - 6:00pm", + "formatted_hours_plain_text": "7:30am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -450,6 +475,7 @@ "string_date": "Thu, Mar 26, 2020", "sortable_date": "2020-03-26", "formatted_hours": "7:30am - 6:00pm", + "formatted_hours_plain_text": "7:30am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -467,6 +493,7 @@ "string_date": "Fri, Mar 27, 2020", "sortable_date": "2020-03-27", "formatted_hours": "7:30am - 6:00pm", + "formatted_hours_plain_text": "7:30am - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -484,6 +511,7 @@ "string_date": "Sat, Mar 28, 2020", "sortable_date": "2020-03-28", "formatted_hours": "1:00pm - 6:00pm", + "formatted_hours_plain_text": "1:00pm - 6:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -501,6 +529,7 @@ "string_date": "Sun, Mar 29, 2020", "sortable_date": "2020-03-29", "formatted_hours": "1:00pm - 10:00pm", + "formatted_hours_plain_text": "1:00pm - 10:00pm", "open_all_day": false, "closes_at_night": true, "event_desc": "", @@ -517,7 +546,8 @@ "close": "11:59pm", "string_date": "Mon, Mar 30, 2020", "sortable_date": "2020-03-30", - "formatted_hours": "7:30am - 12:00am", + "formatted_hours": "7:30am - No closing", + "formatted_hours_plain_text": "7:30am - No closing", "open_all_day": false, "closes_at_night": false, "event_desc": "", @@ -535,6 +565,7 @@ "string_date": "Tue, Mar 31, 2020", "sortable_date": "2020-03-31", "formatted_hours": "Open 24 Hours", + "formatted_hours_plain_text": "Open 24 Hours", "open_all_day": true, "closes_at_night": false, "event_desc": "", diff --git a/spec/fixtures/alma_march_2020_raw.json b/spec/fixtures/alma_march_2020_raw.json index f93d90c..c1d3d12 100644 --- a/spec/fixtures/alma_march_2020_raw.json +++ b/spec/fixtures/alma_march_2020_raw.json @@ -545,5 +545,7 @@ ] } ] + }, + "2020-04-01T00:00:00+00:00": { } } diff --git a/spec/fixtures/alma_may_2019_raw.json b/spec/fixtures/alma_may_2019_raw.json index 13edc86..fd5fc95 100644 --- a/spec/fixtures/alma_may_2019_raw.json +++ b/spec/fixtures/alma_may_2019_raw.json @@ -522,5 +522,7 @@ ] } ] + }, + "2019-06-01T00:00:00+00:00": { } } diff --git a/spec/models/alma_spec.rb b/spec/models/alma_spec.rb index db13cc2..651733a 100644 --- a/spec/models/alma_spec.rb +++ b/spec/models/alma_spec.rb @@ -6,7 +6,9 @@ let(:alma) { described_class.new(date_from: date_from, date_to: date_to, limited: false) } let(:base_url) { ENV['ALMA_OPEN_HOURS_URL'].to_s } let(:alma_key) { ENV['ALMA_API_KEY'].to_s } + let(:next_day) { DateTime.parse(date_to).next_day.strftime('%Y-%m-%d') } let(:url) { "#{base_url}?apikey=#{alma_key}&from=#{date_from}&to=#{date_to}" } + let(:url_next) { "#{base_url}?apikey=#{alma_key}&from=#{next_day}&to=#{next_day}" } let(:raw_json) do { 'day': [ @@ -26,8 +28,8 @@ ] }.to_json end - let(:date_from) { '2018-06-24' } - let(:date_to) { '2018-06-24' } + let(:date_from) { '2019-06-24' } + let(:date_to) { '2019-06-24' } let(:cached_minutes) { '1' } before do @@ -43,6 +45,14 @@ 'User-Agent' => 'Ruby' } ).to_return(status: 200, body: raw_json, headers: {}) + stub_request(:get, url_next) + .with( + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'User-Agent' => 'Ruby' + } + ).to_return(status: 200, body: raw_json, headers: {}) end it 'sets a hash variable' do diff --git a/spec/services/api/library_open_hours_json_spec.rb b/spec/services/api/library_open_hours_json_spec.rb index 2da2b35..962b01a 100644 --- a/spec/services/api/library_open_hours_json_spec.rb +++ b/spec/services/api/library_open_hours_json_spec.rb @@ -11,7 +11,7 @@ describe '#call' do context 'outputs valid JSON between 2019-05-01 and 2019-05-31' do - MAY_TEST_DATES = (DateTime.parse('2019-05-01')..DateTime.parse('2019-05-31')).to_a.map {|d| d.strftime('%Y-%m-%d') } + MAY_TEST_DATES = (DateTime.parse('2019-05-01')..DateTime.parse('2019-06-01')).to_a.map {|d| d.strftime('%Y-%m-%d') } MAY_TEST_DATES.each do |date| it "outputs JSON in a valid format for #{date}" do date_val = DateTime.parse(date).to_s @@ -25,7 +25,7 @@ let(:api_input_json) { File.read('spec/fixtures/alma_june_2019_raw.json') } let(:api_output_json) { File.read('spec/fixtures/alma_june_2019.json') } - JUNE_TEST_DATES = (DateTime.parse('2019-06-01')..DateTime.parse('2019-06-30')).to_a.map {|d| d.strftime('%Y-%m-%d') } + JUNE_TEST_DATES = (DateTime.parse('2019-06-01')..DateTime.parse('2019-07-01')).to_a.map {|d| d.strftime('%Y-%m-%d') } JUNE_TEST_DATES.each do |date| it "outputs JSON in a valid format for #{date}" do date_val = DateTime.parse(date).to_s @@ -40,7 +40,7 @@ let(:api_input_json) { File.read('spec/fixtures/alma_january_2020_raw.json') } let(:api_output_json) { File.read('spec/fixtures/alma_january_2020.json') } - JANUARY_TEST_DATES = (DateTime.parse('2020-01-01')..DateTime.parse('2020-01-31')).to_a.map { |d| d.strftime('%Y-%m-%d') } + JANUARY_TEST_DATES = (DateTime.parse('2020-01-01')..DateTime.parse('2020-02-01')).to_a.map { |d| d.strftime('%Y-%m-%d') } JANUARY_TEST_DATES.each do |date| it "outputs JSON in a valid format for #{date}" do date_val = DateTime.parse(date).to_s @@ -49,5 +49,20 @@ end end end + + # Closing at midnight on friday and saturday + context 'outputs valid JSON between 2020-03-01 and 2020-03-31' do + let(:api_input_json) { File.read('spec/fixtures/alma_march_2020_raw.json') } + let(:api_output_json) { File.read('spec/fixtures/alma_march_2020.json') } + + MARCH_TEST_DATES = (DateTime.parse('2020-03-01')..DateTime.parse('2020-04-01')).to_a.map { |d| d.strftime('%Y-%m-%d') } + MARCH_TEST_DATES.each do |date| + it "outputs JSON in a valid format for #{date}" do + date_val = DateTime.parse(date).to_s + expected_date_json = expected_json[date_val] + expect(JSON.parse(service.call(raw_hours, true))[date_val]).to eq expected_date_json + end + end + end end end