aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcedricnjanga2017-12-14 18:47:44 +0100
committerLuc Donnet2017-12-21 13:54:07 +0100
commitf2d00fad59d97130babc95f37d495245f3d53f80 (patch)
tree97b100f22b716ed00fd456b8834d80db129a9981
parent7f9a61d5823bd6611351fcc6dce79a2159976b34 (diff)
downloadchouette-core-f2d00fad59d97130babc95f37d495245f3d53f80.tar.bz2
Refs #5301 First draft for Business Calendars
-rw-r--r--app/controllers/business_calendars_controller.rb33
-rw-r--r--app/decorators/business_calendar_decorator.rb25
-rw-r--r--app/models/business_calendar.rb35
-rw-r--r--app/models/calendar.rb156
-rw-r--r--app/models/concerns/calendar_support.rb159
-rw-r--r--app/policies/business_calendar_policy.rb20
-rw-r--r--app/views/business_calendars/_filters.html.slim18
-rw-r--r--app/views/business_calendars/_form.html.slim47
-rw-r--r--app/views/business_calendars/index.html.slim48
-rw-r--r--app/views/business_calendars/new.html.slim6
-rw-r--r--app/views/dashboards/_dashboard.html.slim14
-rw-r--r--config/breadcrumbs.rb9
-rw-r--r--config/routes.rb2
-rw-r--r--db/migrate/20171214131755_create_business_calendars.rb13
-rw-r--r--db/schema.rb12
-rw-r--r--lib/stif/permission_translator.rb1
-rw-r--r--spec/factories/business_calendars.rb8
-rw-r--r--spec/models/business_calendar_spec.rb5
18 files changed, 456 insertions, 155 deletions
diff --git a/app/controllers/business_calendars_controller.rb b/app/controllers/business_calendars_controller.rb
new file mode 100644
index 000000000..ee990dfba
--- /dev/null
+++ b/app/controllers/business_calendars_controller.rb
@@ -0,0 +1,33 @@
+class BusinessCalendarsController < ChouetteController
+ include PolicyChecker
+ include RansackDateFilter
+ defaults resource_class: BusinessCalendar
+ before_action only: [:index] { set_date_time_params("bounding_dates", Date) }
+
+ def index
+ index! do
+ scope = self.ransack_period_range(scope: @business_calendars, error_message: t('compliance_check_sets.filters.error_period_filter'), query: :overlapping)
+ @q = scope.ransack(params[:q])
+ @business_calendars = decorate_business_calendars(@q.result.paginate(page: params[:page], per_page: 30))
+ end
+ end
+
+ def show
+ show! do
+ @business_calendar = @business_calendar.decorate
+ end
+ end
+
+ private
+
+ def business_calendar_params
+ permitted_params = [:id, :name, :short_name, periods_attributes: [:id, :begin, :end, :_destroy], date_values_attributes: [:id, :value, :_destroy]]
+ params.require(:business_calendar).permit(*permitted_params)
+ end
+
+ def decorate_business_calendars(business_calendars)
+ ModelDecorator.decorate(
+ business_calendars,
+ with: BusinessCalendarDecorator)
+ end
+end \ No newline at end of file
diff --git a/app/decorators/business_calendar_decorator.rb b/app/decorators/business_calendar_decorator.rb
new file mode 100644
index 000000000..9e8f21572
--- /dev/null
+++ b/app/decorators/business_calendar_decorator.rb
@@ -0,0 +1,25 @@
+class BusinessCalendarDecorator < Draper::Decorator
+ delegate_all
+
+ def action_links
+ links = []
+
+ if h.policy(object).update?
+ links << Link.new(
+ content: h.update_link_content,
+ href: h.edit_business_calendar_path(object)
+ )
+ end
+
+ if h.policy(object).destroy?
+ links << Link.new(
+ content: h.destroy_link_content,
+ href: h.calendar_path(object),
+ method: :delete,
+ data: { confirm: h.t('calendars.actions.destroy_confirm') }
+ )
+ end
+
+ links
+ end
+end \ No newline at end of file
diff --git a/app/models/business_calendar.rb b/app/models/business_calendar.rb
new file mode 100644
index 000000000..0064b4537
--- /dev/null
+++ b/app/models/business_calendar.rb
@@ -0,0 +1,35 @@
+require 'range_ext'
+require_relative 'calendar/date_value'
+require_relative 'calendar/period'
+
+class BusinessCalendar < ActiveRecord::Base
+ include CalendarSupport
+
+ scope :overlapping, -> (period_range) do
+ where("(periods.begin <= :end AND periods.end >= :begin) OR (dates BETWEEN :begin AND :end)", {begin: period_range.begin, end: period_range.end})
+ end
+
+ def bounding_dates
+ bounding_min = self.dates.min
+ bounding_max = self.dates.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 periods_max_date
+ return nil if self.periods.empty?
+ self.periods.max.end
+ end
+
+ def periods_min_date
+ return nil if self.periods.empty?
+ self.periods.min.begin
+ end
+
+end \ No newline at end of file
diff --git a/app/models/calendar.rb b/app/models/calendar.rb
index b2e73929f..4e8cd0977 100644
--- a/app/models/calendar.rb
+++ b/app/models/calendar.rb
@@ -3,22 +3,10 @@ require_relative 'calendar/date_value'
require_relative 'calendar/period'
class Calendar < ActiveRecord::Base
- has_paper_trail
- belongs_to :organisation
- has_many :time_tables
-
- validates_presence_of :name, :short_name, :organisation
- validates_uniqueness_of :short_name
-
- after_initialize :init_dates_and_date_ranges
-
+ include CalendarSupport
+
scope :contains_date, ->(date) { where('date ? = any (dates) OR date ? <@ any (date_ranges)', date, date) }
- def init_dates_and_date_ranges
- self.dates ||= []
- self.date_ranges ||= []
- end
-
def self.ransackable_scopes(auth_object = nil)
[:contains_date]
end
@@ -35,144 +23,4 @@ class Calendar < ActiveRecord::Base
end
end
-
- ### Calendar::Period
- # Required by coocon
- def build_period
- Calendar::Period.new
- end
-
- def periods
- @periods ||= init_periods
- end
-
- def init_periods
- (date_ranges || [])
- .each_with_index
- .map( &Calendar::Period.method(:from_range) )
- end
- private :init_periods
-
- validate :validate_periods
-
- def validate_periods
- periods_are_valid = periods.all?(&:valid?)
-
- periods.each do |period|
- if period.intersect?(periods)
- period.errors.add(:base, I18n.t('calendars.errors.overlapped_periods'))
- periods_are_valid = false
- end
- end
-
- unless periods_are_valid
- errors.add(:periods, :invalid)
- end
- end
-
- def flatten_date_array attributes, key
- date_int = %w(1 2 3).map {|e| attributes["#{key}(#{e}i)"].to_i }
- Date.new(*date_int)
- end
-
- def periods_attributes=(attributes = {})
- @periods = []
- attributes.each do |index, period_attribute|
- # Convert date_select to date
- ['begin', 'end'].map do |attr|
- period_attribute[attr] = flatten_date_array(period_attribute, attr)
- end
- period = Calendar::Period.new(period_attribute.merge(id: index))
- @periods << period unless period.marked_for_destruction?
- end
-
- date_ranges_will_change!
- end
-
- before_validation :fill_date_ranges
-
- def fill_date_ranges
- if @periods
- self.date_ranges = @periods.map(&:range).compact.sort_by(&:begin)
- end
- end
-
- after_save :clear_periods
-
- def clear_periods
- @periods = nil
- end
-
- private :clear_periods
-
- ### Calendar::DateValue
-
- # Required by coocon
- def build_date_value
- Calendar::DateValue.new
- end
-
- def date_values
- @date_values ||= init_date_values
- end
-
- def init_date_values
- if dates
- dates.each_with_index.map { |d, index| Calendar::DateValue.from_date(index, d) }
- else
- []
- end
- end
- private :init_date_values
-
- validate :validate_date_values
-
- def validate_date_values
- date_values_are_valid = date_values.all?(&:valid?)
-
- date_values.each do |date_value|
- if date_values.count { |d| d.value == date_value.value } > 1
- date_value.errors.add(:base, I18n.t('activerecord.errors.models.calendar.attributes.dates.date_in_dates'))
- 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
- end
- end
- end
-
- unless date_values_are_valid
- errors.add(:date_values, :invalid)
- end
- end
-
- def date_values_attributes=(attributes = {})
- @date_values = []
- attributes.each do |index, date_value_attribute|
- date_value_attribute['value'] = flatten_date_array(date_value_attribute, 'value')
- date_value = Calendar::DateValue.new(date_value_attribute.merge(id: index))
- @date_values << date_value unless date_value.marked_for_destruction?
- end
-
- dates_will_change!
- end
-
- before_validation :fill_dates
-
- def fill_dates
- if @date_values
- self.dates = @date_values.map(&:value).compact.sort
- end
- end
-
- after_save :clear_date_values
-
- def clear_date_values
- @date_values = nil
- end
-
- private :clear_date_values
-
end
diff --git a/app/models/concerns/calendar_support.rb b/app/models/concerns/calendar_support.rb
new file mode 100644
index 000000000..411acb949
--- /dev/null
+++ b/app/models/concerns/calendar_support.rb
@@ -0,0 +1,159 @@
+module CalendarSupport
+ extend ActiveSupport::Concern
+
+ included do
+ has_paper_trail
+ belongs_to :organisation
+ has_many :time_tables
+
+ validates_presence_of :name, :short_name, :organisation
+ validates_uniqueness_of :short_name
+ after_initialize :init_dates_and_date_ranges
+
+
+ def init_dates_and_date_ranges
+ self.dates ||= []
+ binding.pry
+ self.date_ranges ||= []
+ end
+ ### Calendar::Period
+ # Required by coocon
+ def build_period
+ Calendar::Period.new
+ end
+
+ def periods
+ binding.pry
+ @periods ||= init_periods
+ end
+
+ def init_periods
+ (date_ranges || [])
+ .each_with_index
+ .map( &Calendar::Period.method(:from_range) )
+ end
+ private :init_periods
+
+ validate :validate_periods
+
+ def validate_periods
+ periods_are_valid = periods.all?(&:valid?)
+
+ periods.each do |period|
+ if period.intersect?(periods)
+ period.errors.add(:base, I18n.t('calendars.errors.overlapped_periods'))
+ periods_are_valid = false
+ end
+ end
+
+ unless periods_are_valid
+ errors.add(:periods, :invalid)
+ end
+ end
+
+ def flatten_date_array attributes, key
+ date_int = %w(1 2 3).map {|e| attributes["#{key}(#{e}i)"].to_i }
+ Date.new(*date_int)
+ end
+
+ def periods_attributes=(attributes = {})
+ @periods = []
+ attributes.each do |index, period_attribute|
+ # Convert date_select to date
+ ['begin', 'end'].map do |attr|
+ period_attribute[attr] = flatten_date_array(period_attribute, attr)
+ end
+ period = Calendar::Period.new(period_attribute.merge(id: index))
+ @periods << period unless period.marked_for_destruction?
+ end
+
+ date_ranges_will_change!
+ end
+
+ before_validation :fill_date_ranges
+
+ def fill_date_ranges
+ if @periods
+ self.date_ranges = @periods.map(&:range).compact.sort_by(&:begin)
+ end
+ end
+
+ after_save :clear_periods
+
+ def clear_periods
+ @periods = nil
+ end
+
+ private :clear_periods
+
+ ### Calendar::DateValue
+
+ # Required by coocon
+ def build_date_value
+ Calendar::DateValue.new
+ end
+
+ def date_values
+ @date_values ||= init_date_values
+ end
+
+ def init_date_values
+ if dates
+ dates.each_with_index.map { |d, index| Calendar::DateValue.from_date(index, d) }
+ else
+ []
+ end
+ end
+ private :init_date_values
+
+ validate :validate_date_values
+
+ def validate_date_values
+ date_values_are_valid = date_values.all?(&:valid?)
+
+ date_values.each do |date_value|
+ if date_values.count { |d| d.value == date_value.value } > 1
+ date_value.errors.add(:base, I18n.t('activerecord.errors.models.calendar.attributes.dates.date_in_dates'))
+ 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
+ end
+ end
+ end
+
+ unless date_values_are_valid
+ errors.add(:date_values, :invalid)
+ end
+ end
+
+ def date_values_attributes=(attributes = {})
+ @date_values = []
+ attributes.each do |index, date_value_attribute|
+ date_value_attribute['value'] = flatten_date_array(date_value_attribute, 'value')
+ date_value = Calendar::DateValue.new(date_value_attribute.merge(id: index))
+ @date_values << date_value unless date_value.marked_for_destruction?
+ end
+
+ dates_will_change!
+ end
+
+ before_validation :fill_dates
+
+ def fill_dates
+ if @date_values
+ self.dates = @date_values.map(&:value).compact.sort
+ end
+ end
+
+ after_save :clear_date_values
+
+ def clear_date_values
+ @date_values = nil
+ end
+
+ private :clear_date_values
+ end
+end \ No newline at end of file
diff --git a/app/policies/business_calendar_policy.rb b/app/policies/business_calendar_policy.rb
new file mode 100644
index 000000000..6be40f20f
--- /dev/null
+++ b/app/policies/business_calendar_policy.rb
@@ -0,0 +1,20 @@
+class BusinessCalendarPolicy < ApplicationPolicy
+ class Scope < Scope
+ def resolve
+ scope
+ end
+ end
+
+ def create?
+ user.has_permission?('business_calendars.create')
+ end
+
+ def destroy?
+ organisation_match? && user.has_permission?('business_calendars.destroy')
+ end
+
+ def update?
+ organisation_match? && user.has_permission?('business_calendars.update')
+ end
+
+end \ No newline at end of file
diff --git a/app/views/business_calendars/_filters.html.slim b/app/views/business_calendars/_filters.html.slim
new file mode 100644
index 000000000..8bc9ac2ae
--- /dev/null
+++ b/app/views/business_calendars/_filters.html.slim
@@ -0,0 +1,18 @@
+= search_form_for @q, url: business_calendars_path, builder: SimpleForm::FormBuilder, html: { method: :get, class: 'form form-filter' } do |f|
+ .ffg-row
+ .input-group.search_bar
+ = f.search_field :name_cont, class: 'form-control', placeholder: 'Indiquez un nom de calendrier commercial...'
+ span.input-group-btn
+ button.btn.btn-default#search_btn type='submit'
+ span.fa.fa-search
+
+ .form-group.togglable
+ = f.label BusinessCalendar.human_attribute_name(:bounding_dates), required: false, class: 'control-label'
+ .filter_menu
+ = f.simple_fields_for :bounding_dates do |p|
+ = p.input :start_date, as: :date, label: t('simple_form.from'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @begin_range, include_blank: @begin_range ? false : true
+ = p.input :end_date, as: :date, label: t('simple_form.to'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @end_range, include_blank: @end_range ? false : true
+
+ .actions
+ = link_to 'Effacer', business_calendars_path, class: 'btn btn-link'
+ = f.submit 'Filtrer', id: 'calendar_filter_btn', class: 'btn btn-default'
diff --git a/app/views/business_calendars/_form.html.slim b/app/views/business_calendars/_form.html.slim
new file mode 100644
index 000000000..c2c9fb3a1
--- /dev/null
+++ b/app/views/business_calendars/_form.html.slim
@@ -0,0 +1,47 @@
+= simple_form_for @business_calendar, html: { class: 'form-horizontal', id: 'business_calendar_form' }, wrapper: :horizontal_form do |f|
+ .row
+ .col-lg-12
+ = f.input :name
+
+ .separator
+
+ .row
+ .col-lg-12
+ .subform
+ .nested-head
+ .wrapper
+ div
+ .form-group
+ label.control-label
+ = BusinessCalendar.human_attribute_name(:date)
+ div
+
+ = f.simple_fields_for :date_values do |date_value|
+ = render 'calendars/date_fields', f: date_value
+
+ .links.nested-linker
+ = link_to_add_association t('simple_form.labels.calendar.add_a_date'), f, :dates, class: 'btn btn-outline-primary'
+
+ .separator
+
+ .row
+ .col-lg-12
+ .subform
+ .nested-head
+ .wrapper
+ div
+ .form-group
+ label.control-label
+ = t('simple_form.labels.calendar.ranges.begin')
+ div
+ .form-group
+ label.control-label
+ = t('simple_form.labels.calendar.ranges.end')
+ div
+
+ = f.simple_fields_for :periods do |period|
+ = render 'period_fields', f: period
+ .links.nested-linker
+ = link_to_add_association t('simple_form.labels.calendar.add_a_date_range'), f, :periods, class: 'btn btn-outline-primary'
+
+ = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'business_calendar_form'
diff --git a/app/views/business_calendars/index.html.slim b/app/views/business_calendars/index.html.slim
new file mode 100644
index 000000000..ce7f2343b
--- /dev/null
+++ b/app/views/business_calendars/index.html.slim
@@ -0,0 +1,48 @@
+- breadcrumb :business_calendars
+- content_for :page_header_actions do
+ - if policy(BusinessCalendar).create?
+ = link_to(t('actions.add'), new_business_calendar_path, class: 'btn btn-default')
+
+.page_content
+ .container-fluid
+ - if params[:q].present? or @business_calendars.any?
+ .row
+ .col-lg-12
+ = render 'filters'
+
+ - if @business_calendars.any?
+ .row
+ .col-lg-12
+ = table_builder_2 @business_calendars,
+ [ \
+ TableBuilderHelper::Column.new( \
+ key: :name, \
+ attribute: 'name', \
+ link_to: lambda do |business_calendar| \
+ calendar_path(business_calendar) \
+ end \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :color, \
+ attribute: 'color'\
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :created_at, \
+ attribute: 'created_at' \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :updated_at, \
+ attribute: 'updated_at' \
+ ) \
+ ],
+ links: [:show, :edit],
+ cls: 'table has-filter'
+
+ = new_pagination @business_calendars, 'pull-right'
+
+ - unless @business_calendars.any?
+ .row.mt-xs
+ .col-lg-12
+ = replacement_msg t('calendars.search_no_results')
+
+= javascript_pack_tag 'date_filters'
diff --git a/app/views/business_calendars/new.html.slim b/app/views/business_calendars/new.html.slim
new file mode 100644
index 000000000..ee44609ba
--- /dev/null
+++ b/app/views/business_calendars/new.html.slim
@@ -0,0 +1,6 @@
+- breadcrumb :business_calendars
+.page_content
+ .container-fluid
+ .row
+ .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
+ = render 'form'
diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim
index 7d547bf4c..27d23cfc1 100644
--- a/app/views/dashboards/_dashboard.html.slim
+++ b/app/views/dashboards/_dashboard.html.slim
@@ -33,6 +33,20 @@
.panel-body
em.small.text-muted Aucun modèle de calendrier défini
+ .panel.panel-default
+ .panel-heading
+ h3.panel-title.with_actions
+ = "Calendriers commerciaux"
+ div
+ = link_to '', business_calendars_path, class: ' fa fa-chevron-right pull-right'
+ - if @dashboard.current_organisation.business_calendars.present?
+ .list-group
+ - @dashboard.current_organisation.business_calendars.order("updated_at desc").limit(5).each do |business_calendar|
+ = link_to business_calendar.name, business_calendar_path(business_calendar), class: 'list-group-item'
+ - else
+ .panel-body
+ em.small.text-muted Aucun calendrier commercial défini
+
.col-lg-6.col-md-6.col-sm-6.col-xs-12
.panel.panel-default
.panel-heading
diff --git a/config/breadcrumbs.rb b/config/breadcrumbs.rb
index eb285b731..1a252273b 100644
--- a/config/breadcrumbs.rb
+++ b/config/breadcrumbs.rb
@@ -162,6 +162,15 @@ crumb :line do |line|
parent :lines, line.line_referential
end
+crumb :business_calendars do
+ link I18n.t('business_calendars.index.title'), business_calendars_path
+end
+
+crumb :business_calendar do |calendar|
+ link breadcrumb_name(business_calendar), business_calendar_path(business_calendar)
+ parent :business_calendars
+end
+
crumb :calendars do
link I18n.t('calendars.index.title'), calendars_path
end
diff --git a/config/routes.rb b/config/routes.rb
index 65fa62557..b4191da0f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -99,6 +99,8 @@ ChouetteIhm::Application.routes.draw do
resources :networks
end
+ resources :business_calendars
+
resources :calendars do
get :autocomplete, on: :collection, controller: 'autocomplete_calendars'
end
diff --git a/db/migrate/20171214131755_create_business_calendars.rb b/db/migrate/20171214131755_create_business_calendars.rb
new file mode 100644
index 000000000..5bb3db9d3
--- /dev/null
+++ b/db/migrate/20171214131755_create_business_calendars.rb
@@ -0,0 +1,13 @@
+class CreateBusinessCalendars < ActiveRecord::Migration
+ def change
+ create_table :business_calendars do |t|
+ t.string :name
+ t.string :short_name
+ t.string :color
+ t.date :dates
+ t.daterange :date_ranges
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f2642f8fc..a51a3bb42 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -81,6 +81,16 @@ ActiveRecord::Schema.define(version: 20171214130636) do
add_index "api_keys", ["organisation_id"], name: "index_api_keys_on_organisation_id", using: :btree
+ create_table "business_calendars", id: :bigserial, force: :cascade do |t|
+ t.string "name"
+ t.string "short_name"
+ t.string "color"
+ t.date "dates"
+ t.daterange "date_ranges"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "calendars", id: :bigserial, force: :cascade do |t|
t.string "name"
t.string "short_name"
@@ -403,9 +413,9 @@ ActiveRecord::Schema.define(version: 20171214130636) do
t.string "type"
t.integer "parent_id", limit: 8
t.string "parent_type"
- t.datetime "notified_parent_at"
t.integer "current_step", default: 0
t.integer "total_steps", default: 0
+ t.datetime "notified_parent_at"
t.string "creator"
end
diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb
index 4acf42884..b93396cc3 100644
--- a/lib/stif/permission_translator.rb
+++ b/lib/stif/permission_translator.rb
@@ -18,6 +18,7 @@ module Stif
%w[
access_points
connection_links
+ business_calendars
calendars
footnotes
imports
diff --git a/spec/factories/business_calendars.rb b/spec/factories/business_calendars.rb
new file mode 100644
index 000000000..309cc18f4
--- /dev/null
+++ b/spec/factories/business_calendars.rb
@@ -0,0 +1,8 @@
+FactoryGirl.define do
+ factory :business_calendar do
+ name "MyString"
+ color "MyString"
+ dates "2017-12-14"
+ periods ""
+ end
+end
diff --git a/spec/models/business_calendar_spec.rb b/spec/models/business_calendar_spec.rb
new file mode 100644
index 000000000..29f67d49f
--- /dev/null
+++ b/spec/models/business_calendar_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe BusinessCalendar, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end