aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume2017-09-25 12:38:10 +0200
committerGuillaume2017-09-25 12:38:10 +0200
commit903cc58aa530385f6fc3ceba3bbbacf46f4cd316 (patch)
tree40c20ac148ba804724652976f3639715871b41a1
parent8e543f38ac615a8e5ee7a949ed5c374dfd7a5e32 (diff)
parent76b3b813fb3cafc6880e50a57e823634a79d9a32 (diff)
downloadchouette-core-903cc58aa530385f6fc3ceba3bbbacf46f4cd316.tar.bz2
Merge branch 'master' of https://github.com/af83/stif-boiv
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/form_helper.js62
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/index.js19
-rw-r--r--app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js2
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/actions/index.js79
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js30
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js2
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js10
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js12
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js6
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js6
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js79
-rw-r--r--app/assets/stylesheets/modules/_timetables.sass9
-rw-r--r--app/controllers/compliance_control_sets_controller.rb6
-rw-r--r--app/controllers/imports_controller.rb1
-rw-r--r--app/models/chouette/stif_netex_objectid.rb2
-rw-r--r--app/models/chouette/vehicle_journey_at_stop.rb4
-rw-r--r--app/models/concerns/stif_netex_attributes_support.rb2
-rw-r--r--app/models/referential.rb2
-rw-r--r--app/models/referential_suite.rb6
-rw-r--r--config/locales/vehicle_journey_at_stops.en.yml2
-rw-r--r--config/locales/vehicle_journey_at_stops.fr.yml2
-rw-r--r--db/migrate/20170922161352_create_referential_suites.rb10
-rw-r--r--db/migrate/20170922165315_add_referential_suite_to_referentials.rb8
-rw-r--r--db/schema.rb15
-rw-r--r--lib/model_attribute.rb100
-rw-r--r--spec/javascripts/time_table/actions_spec.js36
-rw-r--r--spec/javascripts/time_table/reducers/modal_spec.js8
-rw-r--r--spec/javascripts/time_table/reducers/pagination_spec.js26
-rw-r--r--spec/javascripts/time_table/reducers/timetable_spec.js147
-rw-r--r--spec/lib/model_attribute_spec.rb117
-rw-r--r--spec/models/chouette/vehicle_journey_at_stop_spec.rb2
-rw-r--r--spec/models/referential_spec.rb1
-rw-r--r--spec/models/referential_suite_spec.rb5
34 files changed, 658 insertions, 166 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index fef3270a3..1d05e0540 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -305,7 +305,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
- mini_portile2 (2.2.0)
+ mini_portile2 (2.3.0)
minitest (5.10.3)
multi_json (1.12.1)
multi_test (0.1.2)
@@ -319,8 +319,8 @@ GEM
net-ssh-gateway (2.0.0)
net-ssh (>= 4.0.0)
newrelic_rpm (4.0.0.332)
- nokogiri (1.8.0)
- mini_portile2 (~> 2.2.0)
+ nokogiri (1.8.1)
+ mini_portile2 (~> 2.3.0)
open4 (1.3.4)
orm_adapter (0.5.0)
parser (2.4.0.0)
diff --git a/app/assets/javascripts/es6_browserified/itineraries/form_helper.js b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
index 0baba27ef..f682e39c0 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/form_helper.js
@@ -1,11 +1,55 @@
-const addInput = (name, value, index) => {
- let form = document.querySelector('form')
- let input = document.createElement('input')
- let formatedName = 'route[stop_points_attributes]['+ index.toString()+']['+name+']'
- input.setAttribute('type', 'hidden')
- input.setAttribute('name', formatedName)
- input.setAttribute('value', value)
- form.appendChild(input)
+const formHelper = {
+ addInput: (name, value, index) => {
+ let form = document.querySelector('form')
+ let input = document.createElement('input')
+ let formatedName = `route[stop_points_attributes][${index.toString()}][${name}]`
+ input.setAttribute('type', 'hidden')
+ input.setAttribute('name', formatedName)
+ input.setAttribute('value', value)
+ form.appendChild(input)
+ },
+ addError: (ids) => {
+ ids.forEach((id) => {
+ if (!$(id).parents('.form-group').hasClass('has-error')) {
+ $(id).parents('.form-group').addClass('has-error')
+ $(id).parent().append(`<span class='help-block small'>${'doit être rempli(e)'}</span>`)
+ }
+ })
+ },
+ cleanInputs: (ids) => {
+ ids.forEach((id) =>{
+ $(id).parents('.form-group').removeClass('has-error')
+ $(id).siblings('span').remove()
+ })
+ },
+ handleForm: (...ids) => {
+ let filledInputs = []
+ let blankInputs = []
+ ids.forEach(id => {
+ $(id).val() == "" ? blankInputs.push(id) : filledInputs.push(id)
+ })
+
+ if (filledInputs.length > 0) formHelper.cleanInputs(filledInputs)
+ if (blankInputs.length > 0) formHelper.addError(blankInputs)
+ },
+ handleStopPoints: (event, state) => {
+ if (state.stopPoints.length >= 2) {
+ state.stopPoints.map((stopPoint, i) => {
+ formHelper.addInput('id', stopPoint.stoppoint_id ? stopPoint.stoppoint_id : '', i)
+ formHelper.addInput('stop_area_id', stopPoint.stoparea_id, i)
+ formHelper.addInput('position', i, i)
+ formHelper.addInput('for_boarding', stopPoint.for_boarding, i)
+ formHelper.addInput('for_alighting', stopPoint.for_alighting, i)
+ })
+ if ($('.alert.alert-danger').length > 0) $('.alert.alert-danger').remove()
+ } else {
+ event.preventDefault()
+ let msg = "L'itinéraire doit comporter au moins deux arrêts"
+ if ($('.alert.alert-danger').length == 0) {
+ $('#stop_points').find('.subform').after(`<div class='alert alert-danger'><span class='fa fa-lg fa-exclamation-circle'></span><span>" ${msg} "</span></div>`)
+ }
+ }
+ }
}
-module.exports = addInput
+module.exports = formHelper \ No newline at end of file
diff --git a/app/assets/javascripts/es6_browserified/itineraries/index.js b/app/assets/javascripts/es6_browserified/itineraries/index.js
index ad32b9519..bb06126f7 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/index.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/index.js
@@ -4,7 +4,7 @@ var Provider = require('react-redux').Provider
var createStore = require('redux').createStore
var reducers = require('./reducers')
var App = require('./components/App')
-var addInput = require('./form_helper')
+var { handleForm, handleStopPoints } = require('./form_helper')
let datas = JSON.parse(decodeURIComponent(window.itinerary_stop))
// logger, DO NOT REMOVE
@@ -67,17 +67,12 @@ render(
document.querySelector('input[name=commit]').addEventListener('click', (event)=>{
let state = store.getState()
- if(state.stopPoints.length >= 2) {
- state.stopPoints.map((stopPoint, i) => {
- addInput('id', stopPoint.stoppoint_id ? stopPoint.stoppoint_id : '', i)
- addInput('stop_area_id',stopPoint.stoparea_id, i)
- addInput('position',i, i)
- addInput('for_boarding',stopPoint.for_boarding, i)
- addInput('for_alighting',stopPoint.for_alighting, i)
- })
- } else {
+ let name = $("#route_name").val()
+ let publicName = $("#route_published_name").val()
+ if (name == "" || publicName == "") {
event.preventDefault()
- let msg = "L'itinéraire doit comporter au moins deux arrêts"
- $('#stop_points').find('.subform').after("<div class='alert alert-danger'><span class='fa fa-lg fa-exclamation-circle'></span><span>" + msg + "</span></div>")
+ handleForm("#route_name", "#route_published_name")
}
+
+ handleStopPoints(event, state)
})
diff --git a/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
index a3b8accb3..f3a26b8d7 100644
--- a/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
+++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js
@@ -1,5 +1,5 @@
var _ = require('lodash')
-var addInput = require('../form_helper')
+var { addInput } = require('../form_helper')
const stopPoint = (state = {}, action, length) => {
switch (action.type) {
diff --git a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
index 02ece1654..ba5d91568 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
@@ -113,14 +113,26 @@ const actions = {
timetableInDates,
error
}),
- includeDateInPeriod: (index, dayTypes, date) => ({
- type: 'INCLUDE_DATE_IN_PERIOD',
+ addIncludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_INCLUDED_DATE',
index,
dayTypes,
date
}),
- excludeDateFromPeriod: (index, dayTypes, date) => ({
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ removeIncludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_INCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ addExcludedDate: (index, dayTypes, date) => ({
+ type: 'ADD_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }),
+ removeExcludedDate: (index, dayTypes, date) => ({
+ type: 'REMOVE_EXCLUDED_DATE',
index,
dayTypes,
date
@@ -157,43 +169,31 @@ const actions = {
let date = new Date(strDate)
return date.toLocaleDateString()
},
+ updateSynthesis: ({current_month, time_table_dates: dates, time_table_periods: periods}) => {
+ let newPeriods = _.reject(periods, 'deleted')
+ let improvedCM = current_month.map((d, i) => {
+ let isInPeriod = actions.isInPeriod(newPeriods, d.date)
+ let isIncluded = _.some(dates, {'date': d.date, 'in_out': true})
- updateSynthesis: (state, daytypes) => {
- let periods = state.time_table_periods
-
- let isInPeriod = function(d){
- let currentMonth = state.current_periode_range.split('-')
- let twodigitsDay = d.mday < 10 ? ('0' + d.mday) : d.mday
- let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay)
-
- // We compare periods & currentDate, to determine if it is included or not
- let testDate = false
- periods.map((p, i) => {
- if (p.deleted) return false
-
- let begin = new Date(p.period_start)
- let end = new Date(p.period_end)
-
- if(testDate === false){
- if(currentDate >= begin && currentDate <= end) {
- testDate = true
- // p.include_date = false
- }
- }
- })
- return testDate
- }
-
- let improvedCM = state.current_month.map((d, i) => {
- let bool = isInPeriod(state.current_month[i])
- return _.assign({}, state.current_month[i], {
- in_periods: bool,
- include_date: bool ? false : state.current_month[i].include_date,
- excluded_date: !bool ? false : state.current_month[i].excluded_date
+ return _.assign({}, current_month[i], {
+ in_periods: isInPeriod,
+ include_date: isIncluded,
+ excluded_date: !isInPeriod ? false : current_month[i].excluded_date
})
})
return improvedCM
},
+ isInPeriod: (periods, date) => {
+ date = new Date(date)
+
+ for (let period of periods) {
+ let begin = new Date(period.period_start)
+ let end = new Date(period.period_end)
+ if (date >= begin && date <= end) return true
+ }
+
+ return false
+ },
checkConfirmModal: (event, callback, stateChanged, dispatch, metas, timetable) => {
if(stateChanged){
const error = actions.errorModalKey(timetable.time_table_periods, metas.day_types)
@@ -318,13 +318,6 @@ const actions = {
}
},
- checkIfTTHasDate: (dates, date) => {
- if (_.some(dates, date)) {
- return _.reject(dates, ['date', date.date])
- } else {
- return dates.concat(date)
- }
- }
}
module.exports = actions
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
index 4879e537f..80c2e4b7a 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
@@ -8,6 +8,15 @@ class ExceptionsInDay extends Component {
super(props)
}
+ handleClick() {
+ const {index, day, metas: {day_types} } = this.props
+ if (day.in_periods && day_types[day.wday]) {
+ day.excluded_date ? this.props.onRemoveExcludedDate(index, day_types, day.date) : this.props.onAddExcludedDate(index, day_types, day.date)
+ } else {
+ day.include_date ? this.props.onRemoveIncludedDate(index, day_types, day.date) : this.props.onAddIncludedDate(index, day_types, day.date)
+ }
+ }
+
render() {
{/* display add or remove link, only if true in daytypes */}
{/* display add or remove link, according to context (presence in period, or not) */}
@@ -20,14 +29,14 @@ class ExceptionsInDay extends Component {
data-actiontype='remove'
onClick={(e) => {
$(e.currentTarget).toggleClass('active')
- this.props.onExcludeDateFromPeriod(this.props.index, this.props.metas.day_types, this.props.currentDate)
+ this.handleClick()
}}
>
<span className='fa fa-times'></span>
</button>
</div>
)
- } else if(this.props.value.current_month[this.props.index].in_periods == false) {
+ } else {
return (
<div className='td'>
<button
@@ -36,20 +45,21 @@ class ExceptionsInDay extends Component {
data-actiontype='add'
onClick={(e) => {
$(e.currentTarget).toggleClass('active')
- this.props.onIncludeDateInPeriod(this.props.index, this.props.metas.day_types, this.props.currentDate)
+ this.handleClick()
}}
>
<span className='fa fa-plus'></span>
</button>
</div>
)
- } else if(this.props.value.current_month[this.props.index].in_periods == true && this.props.blueDaytype == false){
- return (
- <div className='td'></div>
- )
- } else{
- return false
- }
+ // } else if(this.props.value.current_month[this.props.index].in_periods == true && this.props.blueDaytype == false){
+ // return (
+ // <div className='td'></div>
+ // )
+ // } else{
+ // return false
+ // }
+ }
}
}
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
index ca44d3a07..f56509b99 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
@@ -35,7 +35,7 @@ class PeriodsInDay extends Component {
render() {
return (
<div
- className={this.isIn(this.props.currentDate)}
+ className={this.isIn(this.props.currentDate) + (this.props.metas.day_types[this.props.day.wday] || !this.props.day.in_periods ? '' : ' out_from_daytypes')}
>
{this.props.value.map((p, i) => {
if(!p.deleted){
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
index 3af1a11a4..a613549c3 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
@@ -60,13 +60,14 @@ class Timetable extends Component{
{this.props.timetable.current_month.map((d, i) =>
<div
key={i}
- className={'td-group' + (this.props.metas.day_types[d.wday] || !d.in_periods ? '' : ' out_from_daytypes') + (d.wday == 0 ? ' last_wday' : '')}
+ className={'td-group'+ (d.wday == 0 ? ' last_wday' : '')}
>
{/* day_types */}
- <div className="td"></div>
+ <div className={"td" + (this.props.metas.day_types[d.wday] || !d.in_periods ? '' : ' out_from_daytypes') }></div>
{/* periods */}
<PeriodsInDay
+ day={d}
index={i}
value={this.props.timetable.time_table_periods}
currentDate={this.currentDate(this.props.timetable.current_periode_range, d.mday)}
@@ -77,11 +78,16 @@ class Timetable extends Component{
{/* exceptions */}
<ExceptionsInDay
+ day={d}
index={i}
value={this.props.timetable}
currentDate={d.date}
metas={this.props.metas}
blueDaytype={this.props.metas.day_types[d.wday]}
+ onAddIncludedDate={this.props.onAddIncludedDate}
+ onRemoveIncludedDate={this.props.onRemoveIncludedDate}
+ onAddExcludedDate={this.props.onAddExcludedDate}
+ onRemoveExcludedDate={this.props.onRemoveExcludedDate}
onExcludeDateFromPeriod={this.props.onExcludeDateFromPeriod}
onIncludeDateInPeriod={this.props.onIncludeDateInPeriod}
/>
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
index 639a1e2ab..a37e99982 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
@@ -15,6 +15,18 @@ const mapDispatchToProps = (dispatch) => {
onDeletePeriod: (index, dayTypes) =>{
dispatch(actions.deletePeriod(index, dayTypes))
},
+ onAddIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addIncludedDate(index, dayTypes, date))
+ },
+ onRemoveIncludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeIncludedDate(index, dayTypes, date))
+ },
+ onAddExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.addExcludedDate(index, dayTypes, date))
+ },
+ onRemoveExcludedDate: (index, dayTypes, date) => {
+ dispatch(actions.removeExcludedDate(index, dayTypes, date))
+ },
onExcludeDateFromPeriod: (index, dayTypes, date) => {
dispatch(actions.excludeDateFromPeriod(index, dayTypes, date))
},
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
index 2ce084efd..ab5ed3d91 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
@@ -15,8 +15,10 @@ const metas = (state = {}, action) => {
case 'RECEIVE_MONTH':
let dt = (typeof state.day_types === 'string') ? actions.strToArrayDayTypes(state.day_types) : state.day_types
return _.assign({}, state, {day_types: dt})
- case 'INCLUDE_DATE_IN_PERIOD':
- case 'EXCLUDE_DATE_FROM_PERIOD':
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
case 'DELETE_PERIOD':
case 'VALIDATE_PERIOD_FORM':
return _.assign({}, state, {calendar: null})
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
index 45fec6b5f..f38b124d9 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
@@ -20,8 +20,10 @@ const pagination = (state = {}, action) => {
case 'CHANGE_PAGE':
toggleOnConfirmModal()
return _.assign({}, state, {currentPage : action.page, stateChanged: false})
- case 'INCLUDE_DATE_IN_PERIOD':
- case 'EXCLUDE_DATE_FROM_PERIOD':
+ case 'ADD_INCLUDED_DATE':
+ case 'REMOVE_INCLUDED_DATE':
+ case 'ADD_EXCLUDED_DATE':
+ case 'REMOVE_EXCLUDED_DATE':
case 'DELETE_PERIOD':
case 'VALIDATE_PERIOD_FORM':
case 'UPDATE_COMMENT':
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
index 390bdffb0..edb965065 100644
--- a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
@@ -1,7 +1,6 @@
const _ = require('lodash')
var actions = require('../actions')
-let newState = {}
-let newDates = []
+let newState, newPeriods, newDates, newCM
const timetable = (state = {}, action) => {
switch (action.type) {
@@ -11,14 +10,14 @@ const timetable = (state = {}, action) => {
current_periode_range: action.json.current_periode_range,
periode_range: action.json.periode_range,
time_table_periods: action.json.time_table_periods,
- time_table_dates: action.json.time_table_dates
+ time_table_dates: _.sortBy(action.json.time_table_dates, ['date'])
})
- return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState, actions.strToArrayDayTypes(action.json.day_types))})
+ return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState)})
case 'RECEIVE_MONTH':
newState = _.assign({}, state, {
current_month: action.json.days
})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, actions.strToArrayDayTypes(action.json.day_types))})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
case 'GO_TO_PREVIOUS_PAGE':
case 'GO_TO_NEXT_PAGE':
let nextPage = action.nextPage ? 1 : -1
@@ -31,34 +30,44 @@ const timetable = (state = {}, action) => {
actions.fetchTimeTables(action.dispatch, action.page)
return _.assign({}, state, {current_periode_range: action.page})
case 'DELETE_PERIOD':
- let ttperiods = state.time_table_periods.map((period, i) =>{
+ newPeriods = state.time_table_periods.map((period, i) =>{
if(i == action.index){
period.deleted = true
}
return period
})
- newState = _.assign({}, state, {time_table_periods : ttperiods})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
- case 'INCLUDE_DATE_IN_PERIOD':
- newDates = actions.checkIfTTHasDate(state.time_table_dates, {date: action.date, in_out: true})
- let newCMi = state.current_month.map((d, i) => {
- if(i == action.index){
- d.include_date = !d.include_date
- }
+ let deletedPeriod = Array.of(state.time_table_periods[action.index])
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(deletedPeriod, d.date) && !d.in_out)
+ newState = _.assign({}, state, {time_table_periods : newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, { current_month: actions.updateSynthesis(newState)})
+ case 'ADD_INCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: true})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = true
return d
})
- newState = _.assign({}, state, {current_month: newCMi, time_table_dates: newDates})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
- case 'EXCLUDE_DATE_FROM_PERIOD':
- newDates = actions.checkIfTTHasDate(state.time_table_dates, {date: action.date, in_out: false})
- let newCMe = state.current_month.map((d, i) => {
- if(i == action.index){
- d.excluded_date = !d.excluded_date
- }
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_INCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.include_date = false
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'ADD_EXCLUDED_DATE':
+ newDates = state.time_table_dates.concat({date: action.date, in_out: false})
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = true
+ return d
+ })
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
+ case 'REMOVE_EXCLUDED_DATE':
+ newDates = _.reject(state.time_table_dates, ['date', action.date])
+ newCM = state.current_month.map((d, i) => {
+ if (i == action.index) d.excluded_date = false
return d
})
- newState = _.assign({}, state, {current_month: newCMe, time_table_dates: newDates})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
+ return _.assign({}, state, {current_month: newCM, time_table_dates: newDates})
case 'UPDATE_DAY_TYPES':
// We get the week days of the activated day types to reject the out_dates that that are out of newDayTypes
let weekDays = _.reduce(action.dayTypes, (array, dt, i) => {
@@ -67,11 +76,17 @@ const timetable = (state = {}, action) => {
}, [])
newDates = _.reject(state.time_table_dates, (d) => {
- return d.in_out == false && !weekDays.includes(new Date(d.date).getDay())
+ let weekDay = new Date(d.date).getDay()
+
+ if (d.in_out) {
+ return actions.isInPeriod(state.time_table_periods, d.date) && weekDays.includes(weekDay)
+ } else {
+ return !weekDays.includes(weekDay)
+ }
})
return _.assign({}, state, {time_table_dates: newDates})
case 'UPDATE_CURRENT_MONTH_FROM_DAYTYPES':
- return _.assign({}, state, {current_month: actions.updateSynthesis(state, action.dayTypes)})
+ return _.assign({}, state, {current_month: actions.updateSynthesis(state)})
case 'VALIDATE_PERIOD_FORM':
if (action.error != '') return state
@@ -81,8 +96,10 @@ const timetable = (state = {}, action) => {
let newPeriods = JSON.parse(JSON.stringify(action.timeTablePeriods))
if (action.modalProps.index !== false){
- newPeriods[action.modalProps.index].period_start = period_start
- newPeriods[action.modalProps.index].period_end = period_end
+ updatePeriod = newPeriods[action.modalProps.index]
+ updatePeriod.period_start = period_start
+ updatePeriod.period_end = period_end
+ newDates = _.reject(state.time_table_dates, d => actions.isInPeriod(newPeriods, d.date) && !d.in_out)
}else{
let newPeriod = {
period_start: period_start,
@@ -90,8 +107,10 @@ const timetable = (state = {}, action) => {
}
newPeriods.push(newPeriod)
}
- newState =_.assign({}, state, {time_table_periods: newPeriods})
- return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.metas.day_types)})
+
+ newDates = newDates || state.time_table_dates
+ newState =_.assign({}, state, {time_table_periods: newPeriods, time_table_dates: newDates})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState)})
default:
return state
}
diff --git a/app/assets/stylesheets/modules/_timetables.sass b/app/assets/stylesheets/modules/_timetables.sass
index 84f1af043..b06972ef9 100644
--- a/app/assets/stylesheets/modules/_timetables.sass
+++ b/app/assets/stylesheets/modules/_timetables.sass
@@ -85,11 +85,14 @@
&:not(:last-child) > .td
border-right: 2px solid $darkgrey
- &.out_from_daytypes
- background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
- background-size: 25px 25px
+ // &.out_from_daytypes
+ // background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
+ // background-size: 25px 25px
> .td
+ &.out_from_daytypes
+ background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
+ background-size: 25px 25px
&.in_periods
background-color: rgba($gold, 0.5)
border-left-color: rgba($gold, 0.5)
diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb
index 0c6e52f86..c6f4288a9 100644
--- a/app/controllers/compliance_control_sets_controller.rb
+++ b/app/controllers/compliance_control_sets_controller.rb
@@ -26,9 +26,9 @@ class ComplianceControlSetsController < BreadcrumbController
protected
- def begin_of_association_chain
- current_organisation
- end
+ # def begin_of_association_chain
+ # current_organisation
+ # end
private
diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb
index fa8919f20..3333dc535 100644
--- a/app/controllers/imports_controller.rb
+++ b/app/controllers/imports_controller.rb
@@ -89,7 +89,6 @@ class ImportsController < BreadcrumbController
def ransack_status_params
if params[:q]
- binding.pry
return params[:q].delete(:status_eq_any) if params[:q][:status_eq_any].empty? || ( (Import.status.values & params[:q][:status_eq_any]).length >= 4 )
params[:q][:status_eq_any].push("new", "running") if params[:q][:status_eq_any].include?("pending")
params[:q][:status_eq_any].push("aborted", "canceled") if params[:q][:status_eq_any].include?("failed")
diff --git a/app/models/chouette/stif_netex_objectid.rb b/app/models/chouette/stif_netex_objectid.rb
index a0a91668a..93e7a1e85 100644
--- a/app/models/chouette/stif_netex_objectid.rb
+++ b/app/models/chouette/stif_netex_objectid.rb
@@ -3,7 +3,7 @@ class Chouette::StifNetexObjectid < String
parts.present?
end
- @@format = /^([A-Za-z_]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/
+ @@format = /^([A-Za-z_-]+):([A-Za-z]+):([0-9A-Za-z_-]+):([A-Za-z]+)$/
cattr_reader :format
def parts
diff --git a/app/models/chouette/vehicle_journey_at_stop.rb b/app/models/chouette/vehicle_journey_at_stop.rb
index 156cc761f..a4a4a02c8 100644
--- a/app/models/chouette/vehicle_journey_at_stop.rb
+++ b/app/models/chouette/vehicle_journey_at_stop.rb
@@ -41,7 +41,7 @@ module Chouette
:arrival_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: vehicle_journey.objectid.local_id,
+ short_id: vehicle_journey.objectid.short_id,
max: DAY_OFFSET_MAX + 1
)
)
@@ -52,7 +52,7 @@ module Chouette
:departure_day_offset,
I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: vehicle_journey.objectid.local_id,
+ short_id: vehicle_journey.objectid.short_id,
max: DAY_OFFSET_MAX + 1
)
)
diff --git a/app/models/concerns/stif_netex_attributes_support.rb b/app/models/concerns/stif_netex_attributes_support.rb
index 795872755..0d569b613 100644
--- a/app/models/concerns/stif_netex_attributes_support.rb
+++ b/app/models/concerns/stif_netex_attributes_support.rb
@@ -49,7 +49,7 @@ module StifNetexAttributesSupport
end
def provider_id
- self.referential.workbench.organisation.name.parameterize
+ self.referential.workbench.organisation.name.parameterize.underscore
end
def boiv_id
diff --git a/app/models/referential.rb b/app/models/referential.rb
index af08aa868..c7b52ddf8 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -45,6 +45,8 @@ class Referential < ActiveRecord::Base
has_many :stop_areas, through: :stop_area_referential
belongs_to :workbench
+ belongs_to :referential_suite
+
scope :ready, -> { where(ready: true) }
scope :in_periode, ->(periode) { where(id: referential_ids_in_periode(periode)) }
scope :include_metadatas_lines, ->(line_ids) { where('referential_metadata.line_ids && ARRAY[?]::bigint[]', line_ids) }
diff --git a/app/models/referential_suite.rb b/app/models/referential_suite.rb
new file mode 100644
index 000000000..9fd25ef3f
--- /dev/null
+++ b/app/models/referential_suite.rb
@@ -0,0 +1,6 @@
+class ReferentialSuite < ActiveRecord::Base
+ belongs_to :new, class_name: 'Referential'
+ belongs_to :current, class_name: 'Referential'
+
+ has_many :referentials
+end
diff --git a/config/locales/vehicle_journey_at_stops.en.yml b/config/locales/vehicle_journey_at_stops.en.yml
index a96effa2b..8a3bd9394 100644
--- a/config/locales/vehicle_journey_at_stops.en.yml
+++ b/config/locales/vehicle_journey_at_stops.en.yml
@@ -1,4 +1,4 @@
en:
vehicle_journey_at_stops:
errors:
- day_offset_must_not_exceed_max: "The vehicle journey with ID %{local_id} cannot have times exceeding %{max} days"
+ day_offset_must_not_exceed_max: "The vehicle journey with ID %{short_id} cannot have times exceeding %{max} days"
diff --git a/config/locales/vehicle_journey_at_stops.fr.yml b/config/locales/vehicle_journey_at_stops.fr.yml
index 3eff79cf4..f5139fb79 100644
--- a/config/locales/vehicle_journey_at_stops.fr.yml
+++ b/config/locales/vehicle_journey_at_stops.fr.yml
@@ -1,4 +1,4 @@
fr:
vehicle_journey_at_stops:
errors:
- day_offset_must_not_exceed_max: "La course avec l'identifiant %{local_id} ne peut pas avoir des horaires sur plus de %{max} jours"
+ day_offset_must_not_exceed_max: "La course avec l'identifiant %{short_id} ne peut pas avoir des horaires sur plus de %{max} jours"
diff --git a/db/migrate/20170922161352_create_referential_suites.rb b/db/migrate/20170922161352_create_referential_suites.rb
new file mode 100644
index 000000000..5a8693d01
--- /dev/null
+++ b/db/migrate/20170922161352_create_referential_suites.rb
@@ -0,0 +1,10 @@
+class CreateReferentialSuites < ActiveRecord::Migration
+ def change
+ create_table :referential_suites do |t|
+ t.bigint :new_id, index: true
+ t.bigint :current_id, index: true
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/migrate/20170922165315_add_referential_suite_to_referentials.rb b/db/migrate/20170922165315_add_referential_suite_to_referentials.rb
new file mode 100644
index 000000000..a01ba4d40
--- /dev/null
+++ b/db/migrate/20170922165315_add_referential_suite_to_referentials.rb
@@ -0,0 +1,8 @@
+class AddReferentialSuiteToReferentials < ActiveRecord::Migration
+ def change
+ add_reference :referentials, :referential_suite,
+ index: true,
+ foreign_key: true,
+ type: :bigint
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 2b62fa7f1..89f002aee 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170918103913) do
+ActiveRecord::Schema.define(version: 20170922165315) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -602,6 +602,16 @@ ActiveRecord::Schema.define(version: 20170918103913) do
add_index "referential_metadata", ["referential_id"], name: "index_referential_metadata_on_referential_id", using: :btree
add_index "referential_metadata", ["referential_source_id"], name: "index_referential_metadata_on_referential_source_id", using: :btree
+ create_table "referential_suites", id: :bigserial, force: :cascade do |t|
+ t.integer "new_id", limit: 8
+ t.integer "current_id", limit: 8
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "referential_suites", ["current_id"], name: "index_referential_suites_on_current_id", using: :btree
+ add_index "referential_suites", ["new_id"], name: "index_referential_suites_on_new_id", using: :btree
+
create_table "referentials", id: :bigserial, force: :cascade do |t|
t.string "name"
t.string "slug"
@@ -622,9 +632,11 @@ ActiveRecord::Schema.define(version: 20170918103913) do
t.datetime "archived_at"
t.integer "created_from_id", limit: 8
t.boolean "ready", default: false
+ t.integer "referential_suite_id", limit: 8
end
add_index "referentials", ["created_from_id"], name: "index_referentials_on_created_from_id", using: :btree
+ add_index "referentials", ["referential_suite_id"], name: "index_referentials_on_referential_suite_id", using: :btree
create_table "route_sections", id: :bigserial, force: :cascade do |t|
t.integer "departure_id", limit: 8
@@ -987,6 +999,7 @@ ActiveRecord::Schema.define(version: 20170918103913) do
add_foreign_key "journey_patterns", "stop_points", column: "departure_stop_point_id", name: "departure_point_fkey", on_delete: :nullify
add_foreign_key "journey_patterns_stop_points", "journey_patterns", name: "jpsp_jp_fkey", on_delete: :cascade
add_foreign_key "journey_patterns_stop_points", "stop_points", name: "jpsp_stoppoint_fkey", on_delete: :cascade
+ add_foreign_key "referentials", "referential_suites"
add_foreign_key "route_sections", "stop_areas", column: "arrival_id"
add_foreign_key "route_sections", "stop_areas", column: "departure_id"
add_foreign_key "routes", "routes", column: "opposite_route_id", name: "route_opposite_route_fkey"
diff --git a/lib/model_attribute.rb b/lib/model_attribute.rb
new file mode 100644
index 000000000..60580e306
--- /dev/null
+++ b/lib/model_attribute.rb
@@ -0,0 +1,100 @@
+class ModelAttribute
+ attr_reader :klass, :name, :data_type
+
+ def self.all
+ @__all__ ||= []
+ end
+
+ def self.define(klass, name, data_type)
+ all << new(klass, name, data_type)
+ end
+
+ def self.classes
+ all
+ .map(&:klass)
+ .map(&:to_s)
+ .map(&:camelize)
+ .uniq
+ end
+
+ def self.group_by_class
+ all.group_by(&:klass)
+ end
+
+ def self.from_code(code)
+ klass, name = code.split('#').map(&:to_sym)
+
+ methods_by_class(klass).select do |model_attr|
+ model_attr.name == name
+ end.first
+ end
+
+ def self.methods_by_class(klass)
+ all.select do |model_attr|
+ model_attr.klass == klass
+ end
+ end
+
+ def self.methods_by_class_and_type(klass, type)
+ methods_by_class(klass).select do |model_attr|
+ model_attr.data_type == type
+ end
+ end
+
+ def initialize(klass, name, data_type)
+ @klass = klass
+ @name = name
+ @data_type = data_type
+ end
+
+ # Chouette::Route
+ define :route, :name, :string
+ define :route, :published_name, :string
+ define :route, :comment, :string
+ define :route, :number, :string
+ define :route, :direction, :string
+ define :route, :wayback, :string
+
+ # Chouette::JourneyPattern
+ define :journey_pattern, :name, :string
+ define :journey_pattern, :published_name, :string
+ define :journey_pattern, :comment, :string
+ define :journey_pattern, :registration_number, :string
+ define :journey_pattern, :section_status, :integer
+
+ # Chouette::VehicleJourney
+ define :vehicle_journey, :comment, :string
+ define :vehicle_journey, :status_value, :string
+ define :vehicle_journey, :transport_mode, :string
+ define :vehicle_journey, :facility, :string
+ define :vehicle_journey, :published_journey_name, :string
+ define :vehicle_journey, :published_journey_identifier, :string
+ define :vehicle_journey, :vehicle_type_identifier, :string
+ define :vehicle_journey, :number, :integer
+ define :vehicle_journey, :mobility_restricted_suitability, :boolean
+ define :vehicle_journey, :flexible_service, :boolean
+
+ # Chouette::Footnote
+ define :footnote, :code, :string
+ define :footnote, :label, :string
+
+ # Chouette::TimeTable
+ define :time_table, :version, :string
+ define :time_table, :comment, :string
+ define :time_table, :start_date, :date
+ define :time_table, :end_date, :date
+ define :time_table, :color, :string
+
+ # Chouette::RoutingConstraintZone
+ define :routing_constraint_zone, :name, :string
+
+ def code
+ "#{@klass}##{@name}"
+ end
+
+ def ==(other)
+ klass == other.klass &&
+ name == other.name &&
+ data_type == other.data_type
+ end
+end
diff --git a/spec/javascripts/time_table/actions_spec.js b/spec/javascripts/time_table/actions_spec.js
index f052aeece..a7344586d 100644
--- a/spec/javascripts/time_table/actions_spec.js
+++ b/spec/javascripts/time_table/actions_spec.js
@@ -171,28 +171,52 @@ describe('actions', () => {
expect(actions.validatePeriodForm(modalProps, timeTablePeriods, metas, timetableInDates, error)).toEqual(expectedAction)
})
- it('should create an action to include date in period', () => {
+ it('should create an action to add an included date', () => {
let index = 1
let date = actions.formatDate(new Date)
const expectedAction = {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'ADD_INCLUDED_DATE',
index,
dayTypes,
date
}
- expect(actions.includeDateInPeriod(index, dayTypes, date)).toEqual(expectedAction)
+ expect(actions.addIncludedDate(index, dayTypes, date)).toEqual(expectedAction)
})
- it('should create an action to exclude date from period', () => {
+ it('should create an action to remove an included dat', () => {
let index = 1
let date = actions.formatDate(new Date)
const expectedAction = {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'REMOVE_INCLUDED_DATE',
index,
dayTypes,
date
}
- expect(actions.excludeDateFromPeriod(index, dayTypes, date)).toEqual(expectedAction)
+ expect(actions.removeIncludedDate(index, dayTypes, date)).toEqual(expectedAction)
+ })
+
+ it('should create an action to add an excluded date in period', () => {
+ let index = 1
+ let date = actions.formatDate(new Date)
+ const expectedAction = {
+ type: 'ADD_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }
+ expect(actions.addExcludedDate(index, dayTypes, date)).toEqual(expectedAction)
+ })
+
+ it('should create an action to remove an excluded date from period', () => {
+ let index = 1
+ let date = actions.formatDate(new Date)
+ const expectedAction = {
+ type: 'REMOVE_EXCLUDED_DATE',
+ index,
+ dayTypes,
+ date
+ }
+ expect(actions.removeExcludedDate(index, dayTypes, date)).toEqual(expectedAction)
})
it('should create an action to open confirm modal', () => {
diff --git a/spec/javascripts/time_table/reducers/modal_spec.js b/spec/javascripts/time_table/reducers/modal_spec.js
index 570eb85ed..05d58a138 100644
--- a/spec/javascripts/time_table/reducers/modal_spec.js
+++ b/spec/javascripts/time_table/reducers/modal_spec.js
@@ -171,12 +171,14 @@ describe('modal reducer', () => {
let ttperiods = []
let ttdates = []
+ let metas = []
expect(
modalReducer(state, {
type: 'VALIDATE_PERIOD_FORM',
modalProps : modProps,
timeTablePeriods: ttperiods,
+ metas: metas,
timetableInDates: ttdates,
error: 'La date de départ doit être antérieure à la date de fin'
})
@@ -289,9 +291,12 @@ describe('modal reducer', () => {
index: false,
error: ''
}
- let ttperiods3 = []
+ let ttperiods3 = []
let ttdates3 = [{date: "2017-08-04", include_date: true}]
+ let metas = {
+ day_types: [true,true,true,true,true,true,true]
+ }
let newModalProps3 = {
active: true,
@@ -315,6 +320,7 @@ describe('modal reducer', () => {
modalProps : modProps3,
timeTablePeriods: ttperiods3,
timetableInDates: ttdates3,
+ metas: metas,
error: "Une période ne peut chevaucher une date dans un calendrier"
})
).toEqual(Object.assign({}, state3, {modalProps: newModalProps3}))
diff --git a/spec/javascripts/time_table/reducers/pagination_spec.js b/spec/javascripts/time_table/reducers/pagination_spec.js
index 5da58427e..3c1edb9c5 100644
--- a/spec/javascripts/time_table/reducers/pagination_spec.js
+++ b/spec/javascripts/time_table/reducers/pagination_spec.js
@@ -76,20 +76,38 @@ describe('pagination reducer', () => {
).toEqual(Object.assign({}, state, {currentPage : page, stateChanged: false}))
})
- it('should handle INCLUDE_DATE_IN_PERIOD', () => {
+ it('should handle ADD_INCLUDED_DATE', () => {
expect(
paginationReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD'
+ type: 'ADD_INCLUDED_DATE'
})
).toEqual(Object.assign({}, state, {stateChanged: true}))
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD', () => {
+
+ it('should handle REMOVE_INCLUDED_DATE', () => {
+ expect(
+ paginationReducer(state, {
+ type: 'REMOVE_INCLUDED_DATE'
+ })
+ ).toEqual(Object.assign({}, state, {stateChanged: true}))
+ })
+
+ it('should handle ADD_EXCLUDED_DATE', () => {
expect(
paginationReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD'
+ type: 'ADD_EXCLUDED_DATE'
})
).toEqual(Object.assign({}, state, {stateChanged: true}))
})
+
+ it('should handle REMOVE_EXCLUDED_DATE', () => {
+ expect(
+ paginationReducer(state, {
+ type: 'REMOVE_EXCLUDED_DATE'
+ })
+ ).toEqual(Object.assign({}, state, {stateChanged: true}))
+ })
+
it('should handle DELETE_PERIOD', () => {
expect(
paginationReducer(state, {
diff --git a/spec/javascripts/time_table/reducers/timetable_spec.js b/spec/javascripts/time_table/reducers/timetable_spec.js
index 6585a78a0..21f6d236d 100644
--- a/spec/javascripts/time_table/reducers/timetable_spec.js
+++ b/spec/javascripts/time_table/reducers/timetable_spec.js
@@ -6,14 +6,13 @@ const dispatch = function(){}
let arrDayTypes = [true, true, true, true, true, true, true]
let strDayTypes = 'LuMaMeJeVeSaDi'
let time_table_periods = [{"id":261,"period_start":"2017-02-23","period_end":"2017-03-05"},{"id":262,"period_start":"2017-03-15","period_end":"2017-03-25"},{"id":263,"period_start":"2017-04-04","period_end":"2017-04-14"},{"id":264,"period_start":"2017-04-24","period_end":"2017-05-04"},{"id":265,"period_start":"2017-05-14","period_end":"2017-05-24"}]
+let time_table_dates = []
let current_periode_range = "2017-05-01"
let periode_range = ["2014-05-01","2014-06-01","2014-07-01","2014-08-01","2014-09-01","2014-10-01","2014-11-01","2014-12-01","2015-01-01","2015-02-01","2015-03-01","2015-04-01","2015-05-01","2015-06-01","2015-07-01","2015-08-01","2015-09-01","2015-10-01","2015-11-01","2015-12-01","2016-01-01","2016-02-01","2016-03-01","2016-04-01","2016-05-01","2016-06-01","2016-07-01","2016-08-01","2016-09-01","2016-10-01","2016-11-01","2016-12-01","2017-01-01","2017-02-01","2017-03-01","2017-04-01","2017-05-01","2017-06-01","2017-07-01","2017-08-01","2017-09-01","2017-10-01","2017-11-01","2017-12-01","2018-01-01","2018-02-01","2018-03-01","2018-04-01","2018-05-01","2018-06-01","2018-07-01","2018-08-01","2018-09-01","2018-10-01","2018-11-01","2018-12-01","2019-01-01","2019-02-01","2019-03-01","2019-04-01","2019-05-01","2019-06-01","2019-07-01","2019-08-01","2019-09-01","2019-10-01","2019-11-01","2019-12-01","2020-01-01","2020-02-01","2020-03-01","2020-04-01","2020-05-01"]
let current_month = [{"day":"lundi","date":"2017-05-01","wday":1,"wnumber":"18","mday":1,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-02","wday":2,"wnumber":"18","mday":2,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-03","wday":3,"wnumber":"18","mday":3,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-04","wday":4,"wnumber":"18","mday":4,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-05","wday":5,"wnumber":"18","mday":5,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-06","wday":6,"wnumber":"18","mday":6,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-07","wday":0,"wnumber":"18","mday":7,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-08","wday":1,"wnumber":"19","mday":8,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-09","wday":2,"wnumber":"19","mday":9,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-10","wday":3,"wnumber":"19","mday":10,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-11","wday":4,"wnumber":"19","mday":11,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-12","wday":5,"wnumber":"19","mday":12,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-13","wday":6,"wnumber":"19","mday":13,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-14","wday":0,"wnumber":"19","mday":14,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-15","wday":1,"wnumber":"20","mday":15,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-16","wday":2,"wnumber":"20","mday":16,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-17","wday":3,"wnumber":"20","mday":17,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-18","wday":4,"wnumber":"20","mday":18,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-19","wday":5,"wnumber":"20","mday":19,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-20","wday":6,"wnumber":"20","mday":20,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-21","wday":0,"wnumber":"20","mday":21,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-22","wday":1,"wnumber":"21","mday":22,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-23","wday":2,"wnumber":"21","mday":23,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-24","wday":3,"wnumber":"21","mday":24,"include_date":false,"excluded_date":false},{"day":"jeudi","date":"2017-05-25","wday":4,"wnumber":"21","mday":25,"include_date":false,"excluded_date":false},{"day":"vendredi","date":"2017-05-26","wday":5,"wnumber":"21","mday":26,"include_date":false,"excluded_date":false},{"day":"samedi","date":"2017-05-27","wday":6,"wnumber":"21","mday":27,"include_date":false,"excluded_date":false},{"day":"dimanche","date":"2017-05-28","wday":0,"wnumber":"21","mday":28,"include_date":false,"excluded_date":false},{"day":"lundi","date":"2017-05-29","wday":1,"wnumber":"22","mday":29,"include_date":false,"excluded_date":false},{"day":"mardi","date":"2017-05-30","wday":2,"wnumber":"22","mday":30,"include_date":false,"excluded_date":false},{"day":"mercredi","date":"2017-05-31","wday":3,"wnumber":"22","mday":31,"include_date":false,"excluded_date":false}]
let newCurrentMonth = [{"day":"lundi","date":"2017-05-01","wday":1,"wnumber":"18","mday":1,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-02","wday":2,"wnumber":"18","mday":2,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-03","wday":3,"wnumber":"18","mday":3,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-04","wday":4,"wnumber":"18","mday":4,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"vendredi","date":"2017-05-05","wday":5,"wnumber":"18","mday":5,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-06","wday":6,"wnumber":"18","mday":6,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-07","wday":0,"wnumber":"18","mday":7,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"lundi","date":"2017-05-08","wday":1,"wnumber":"19","mday":8,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mardi","date":"2017-05-09","wday":2,"wnumber":"19","mday":9,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mercredi","date":"2017-05-10","wday":3,"wnumber":"19","mday":10,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"jeudi","date":"2017-05-11","wday":4,"wnumber":"19","mday":11,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"vendredi","date":"2017-05-12","wday":5,"wnumber":"19","mday":12,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-13","wday":6,"wnumber":"19","mday":13,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-14","wday":0,"wnumber":"19","mday":14,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"lundi","date":"2017-05-15","wday":1,"wnumber":"20","mday":15,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-16","wday":2,"wnumber":"20","mday":16,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-17","wday":3,"wnumber":"20","mday":17,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-18","wday":4,"wnumber":"20","mday":18,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"vendredi","date":"2017-05-19","wday":5,"wnumber":"20","mday":19,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"samedi","date":"2017-05-20","wday":6,"wnumber":"20","mday":20,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"dimanche","date":"2017-05-21","wday":0,"wnumber":"20","mday":21,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"lundi","date":"2017-05-22","wday":1,"wnumber":"21","mday":22,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mardi","date":"2017-05-23","wday":2,"wnumber":"21","mday":23,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"mercredi","date":"2017-05-24","wday":3,"wnumber":"21","mday":24,"include_date":false,"excluded_date":false,"in_periods":true},{"day":"jeudi","date":"2017-05-25","wday":4,"wnumber":"21","mday":25,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"vendredi","date":"2017-05-26","wday":5,"wnumber":"21","mday":26,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"samedi","date":"2017-05-27","wday":6,"wnumber":"21","mday":27,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"dimanche","date":"2017-05-28","wday":0,"wnumber":"21","mday":28,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"lundi","date":"2017-05-29","wday":1,"wnumber":"22","mday":29,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mardi","date":"2017-05-30","wday":2,"wnumber":"22","mday":30,"include_date":false,"excluded_date":false,"in_periods":false},{"day":"mercredi","date":"2017-05-31","wday":3,"wnumber":"22","mday":31,"include_date":false,"excluded_date":false,"in_periods":false}]
-let time_table_dates = []
-
let json = {
current_month: current_month,
current_periode_range: current_periode_range,
@@ -46,7 +45,7 @@ describe('timetable reducer with empty state', () => {
current_periode_range: current_periode_range,
periode_range: periode_range,
time_table_periods: time_table_periods,
- time_table_dates: time_table_dates
+ time_table_dates: []
}
expect(
timetableReducer(state, {
@@ -125,24 +124,46 @@ describe('timetable reducer with filled state', () => {
).toEqual(Object.assign({}, state, {current_periode_range: newPage}))
})
- it('should handle DELETE_PERIOD', () => {
- state.time_table_periods[0].deleted = true
+ it('should handle DELETE_PERIOD and remove excluded days that were in period', () => {
+ state.time_table_dates.push({date: "2017-05-01", in_out: false})
+ state.current_month[0].excluded_date = true
+ state.time_table_periods[3].deleted = true
+
+ let begin = new Date(state.time_table_periods[3].period_start)
+ let end = new Date(state.time_table_periods[3].period_end)
+
+ let newState = Object.assign({}, state, {
+ time_table_dates: [],
+ current_month: state.current_month.map((d, i) => {
+ if (new Date(d.date) >= begin && new Date(d.date) <= end) {
+ d.excluded_date = false
+ d.in_periods = false
+ }
+ return d
+ })
+ })
expect(
timetableReducer(state, {
type: 'DELETE_PERIOD',
- index: 0,
+ index: 3,
dayTypes: arrDayTypes
})
- ).toEqual(state)
+ ).toEqual(newState)
})
- it('should handle INCLUDE_DATE_IN_PERIOD and add in_day if TT doesnt have it', () => {
+ it('should handle ADD_INCLUDED_DATE', () => {
let newDates = state.time_table_dates.concat({date: "2017-05-05", in_out: true})
- let newState = Object.assign({}, state, {time_table_dates: newDates})
- state.current_month[4].include_date = true
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 4) d.include_date = true
+ return d
+ })
+
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
+
expect(
timetableReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'ADD_INCLUDED_DATE',
index: 4,
dayTypes: arrDayTypes,
date: "2017-05-05"
@@ -150,13 +171,20 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle INCLUDE_DATE_IN_PERIOD and remove in_day if TT has it', () => {
+ it('should handle REMOVE_INCLUDED_DATE', () => {
state.current_month[4].include_date = true
state.time_table_dates.push({date: "2017-05-05", in_out: true})
- let newState = Object.assign({}, state, {time_table_dates: []})
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 4) d.include_date = false
+ return d
+ })
+
+ let newDates = state.time_table_dates.filter(d => d.date != "2017-05-05" && d.in_out != true )
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
expect(
timetableReducer(state, {
- type: 'INCLUDE_DATE_IN_PERIOD',
+ type: 'REMOVE_INCLUDED_DATE',
index: 4,
dayTypes: arrDayTypes,
date: "2017-05-05"
@@ -164,13 +192,22 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD and add out_day if TT doesnt have it', () => {
+ it('should handle ADD_EXCLUDED_DATE', () => {
let newDates = state.time_table_dates.concat({date: "2017-05-01", in_out: false})
- let newState = Object.assign({}, state, {time_table_dates: newDates})
- state.current_month[0].excluded_date = true
+
+ let newCM = newCurrentMonth.map((d,i) => {
+ if (i == 0){
+ d.include_date = false
+ d.excluded_date = true
+ }
+ return d
+ })
+
+ let newState = Object.assign({}, state, {time_table_dates: newDates, current_month: newCM})
+
expect(
timetableReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'ADD_EXCLUDED_DATE',
index: 0,
dayTypes: arrDayTypes,
date: "2017-05-01"
@@ -178,13 +215,13 @@ describe('timetable reducer with filled state', () => {
).toEqual(newState)
})
- it('should handle EXCLUDE_DATE_FROM_PERIOD and remove out_day if TT has it', () => {
+ it('should handle REMOVE_EXCLUDED_DATE', () => {
state.time_table_dates = [{date: "2017-05-01", in_out: false}]
- state.current_month[0].excluded_date = true
+ state.current_month[0].excluded_date = false
let newState = Object.assign({}, state, {time_table_dates: []})
expect(
timetableReducer(state, {
- type: 'EXCLUDE_DATE_FROM_PERIOD',
+ type: 'REMOVE_EXCLUDED_DATE',
index: 0,
dayTypes: arrDayTypes,
date: "2017-05-01"
@@ -194,9 +231,10 @@ describe('timetable reducer with filled state', () => {
it('should handle UPDATE_DAY_TYPES and remove out_day that are out of day types', () => {
state.time_table_dates = [{date: "2017-05-01", in_out: false}]
- let newArrDayTypes = arrDayTypes.slice(0)
- newArrDayTypes[1] = false
- let newState = Object.assign({}, state, {time_table_dates: []})
+ let newArrDayTypes = Array.from(arrDayTypes, (dt, i) => {
+ if (i == 1) dt = false
+ return dt
+ })
expect(
timetableReducer(state, {
type: 'UPDATE_DAY_TYPES',
@@ -205,9 +243,19 @@ describe('timetable reducer with filled state', () => {
).toEqual([])
})
+ it('should handle UPDATE_DAY_TYPES and remove in_day that are in day types and in period', () => {
+ state.time_table_dates = [{ date: "2017-05-16", in_out: true }]
+ expect(
+ timetableReducer(state, {
+ type: 'UPDATE_DAY_TYPES',
+ dayTypes: arrDayTypes
+ }).time_table_dates
+ ).toEqual([])
+ })
+
it('should handle VALIDATE_PERIOD_FORM and add period if modalProps index = false', () => {
let newPeriods = state.time_table_periods.concat({"period_start": "2018-05-15", "period_end": "2018-05-24"})
- let newState = Object.assign({}, state, {time_table_periods: newPeriods})
+ let newState = Object.assign({}, state, {time_table_periods: newPeriods, time_table_dates: []})
let modalProps = {
active: false,
begin: {
@@ -236,4 +284,53 @@ describe('timetable reducer with filled state', () => {
})
).toEqual(newState)
})
+
+ it('should handle VALIDATE_PERIOD_FORM and update period if modalProps index != false', () => {
+
+ let begin = new Date(state.time_table_periods[0].period_start)
+ let end = new Date(state.time_table_periods[0].period_end)
+ let newCM = newCurrentMonth.map((d) => {
+ if (new Date (d.date) >= begin && new Date(d.date) <= end) {
+ d.in_periods = false
+ d.excluded_date = false
+ }
+ return d
+ })
+
+ let newPeriods = state.time_table_periods.map( (p,i) => {
+ if (i == 0) {
+ p.period_start = "2018-05-15"
+ p.period_end = "2018-05-24"
+ }
+ return p
+ })
+ let newState = Object.assign({}, state, {time_table_periods: newPeriods})
+
+ let modalProps = {
+ active: false,
+ begin: {
+ day: '15',
+ month: '05',
+ year: '2018'
+ },
+ end: {
+ day: '24',
+ month: '05',
+ year: '2018'
+ },
+ error: '',
+ index: 0
+ }
+ expect(
+ timetableReducer(state, {
+ type: 'VALIDATE_PERIOD_FORM',
+ modalProps: modalProps,
+ timeTablePeriods: state.time_table_periods,
+ metas: {
+ day_types: arrDayTypes
+ },
+ timetableInDates: state.time_table_dates.filter(d => d.in_out == true)
+ })
+ ).toEqual(newState)
+ })
})
diff --git a/spec/lib/model_attribute_spec.rb b/spec/lib/model_attribute_spec.rb
new file mode 100644
index 000000000..427e01490
--- /dev/null
+++ b/spec/lib/model_attribute_spec.rb
@@ -0,0 +1,117 @@
+RSpec.describe ModelAttribute do
+ describe ".define" do
+ it "adds a new instance of ModelAttribute to .all" do
+ expect do
+ ModelAttribute.define(:route, :name, :string)
+ end.to change { ModelAttribute.all.length }.by(1)
+
+ model_attr = ModelAttribute.all.last
+
+ expect(model_attr).to be_an_instance_of(ModelAttribute)
+ expect(model_attr.klass).to eq(:route)
+ expect(model_attr.name).to eq(:name)
+ expect(model_attr.data_type).to eq(:string)
+ end
+ end
+
+ describe ".classes" do
+ it "returns the list of classes of ModelAttributes in .all" do
+ ModelAttribute.instance_variable_set(:@__all__, [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:journey_pattern, :name, :string),
+ ModelAttribute.new(:time_table, :start_date, :date)
+ ])
+
+ expect(ModelAttribute.classes).to match_array([
+ 'Route',
+ 'JourneyPattern',
+ 'TimeTable'
+ ])
+ end
+ end
+
+ describe ".from_code" do
+ it "returns a ModelAttribute from a given code" do
+ ModelAttribute.instance_variable_set(:@__all__, [
+ ModelAttribute.new(:journey_pattern, :name, :string)
+ ])
+
+ expect(ModelAttribute.from_code('journey_pattern#name')).to eq(
+ ModelAttribute.new(:journey_pattern, :name, :string)
+ )
+ end
+ end
+
+ describe ".group_by_class" do
+ it "returns all ModelAttributes grouped by klass" do
+ ModelAttribute.instance_variable_set(:@__all__, [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ModelAttribute.new(:journey_pattern, :name, :string),
+ ModelAttribute.new(:vehicle_journey, :number, :integer)
+ ])
+
+ expect(ModelAttribute.group_by_class).to eq({
+ route: [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ],
+ journey_pattern: [
+ ModelAttribute.new(:journey_pattern, :name, :string),
+ ],
+ vehicle_journey: [
+ ModelAttribute.new(:vehicle_journey, :number, :integer)
+ ]
+ })
+ end
+ end
+
+ describe ".methods_by_class" do
+ it "returns all ModelAttributes for a given class" do
+ ModelAttribute.instance_variable_set(:@__all__, [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ModelAttribute.new(:route, :direction, :string),
+ ModelAttribute.new(:journey_pattern, :name, :string)
+ ])
+
+ expect(ModelAttribute.methods_by_class(:route)).to match_array([
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :published_name, :string),
+ ModelAttribute.new(:route, :direction, :string)
+ ])
+ end
+ end
+
+ describe ".methods_by_class_and_type" do
+ it "returns ModelAttributes of a certain class and type" do
+ ModelAttribute.instance_variable_set(:@__all__, [
+ ModelAttribute.new(:route, :name, :string),
+ ModelAttribute.new(:route, :checked_at, :date),
+ ModelAttribute.new(:journey_pattern, :name, :string),
+ ModelAttribute.new(:journey_pattern, :section_status, :integer)
+ ])
+
+ expect(ModelAttribute.methods_by_class_and_type(:route, :string)).to match_array([
+ ModelAttribute.new(:route, :name, :string)
+ ])
+ end
+ end
+
+ describe "#code" do
+ it "returns a string representation of the attribute" do
+ model_attr = ModelAttribute.new(:route, :name, :string)
+
+ expect(model_attr.code).to eq('route#name')
+ end
+ end
+
+ describe "#==" do
+ it "returns true when :klass, :name, and :data_type attributes match" do
+ route_name = ModelAttribute.new(:route, :name, :string)
+ other_route_name = ModelAttribute.new(:route, :name, :string)
+
+ expect(route_name == other_route_name).to be true
+ end
+ end
+end
diff --git a/spec/models/chouette/vehicle_journey_at_stop_spec.rb b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
index 4f9d12730..03e6fcb7d 100644
--- a/spec/models/chouette/vehicle_journey_at_stop_spec.rb
+++ b/spec/models/chouette/vehicle_journey_at_stop_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Chouette::VehicleJourneyAtStop, type: :model do
)
error_message = I18n.t(
'vehicle_journey_at_stops.errors.day_offset_must_not_exceed_max',
- local_id: at_stop.vehicle_journey.objectid.local_id,
+ short_id: at_stop.vehicle_journey.objectid.short_id,
max: bad_offset
)
diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb
index f9ace08cc..bb8fabb2e 100644
--- a/spec/models/referential_spec.rb
+++ b/spec/models/referential_spec.rb
@@ -10,6 +10,7 @@ describe Referential, :type => :model do
it { should have_many(:metadatas) }
it { should belong_to(:workbench) }
+ it { should belong_to(:referential_suite) }
context ".referential_ids_in_periode" do
it 'should retrieve referential id in periode range' do
diff --git a/spec/models/referential_suite_spec.rb b/spec/models/referential_suite_spec.rb
new file mode 100644
index 000000000..771187b55
--- /dev/null
+++ b/spec/models/referential_suite_spec.rb
@@ -0,0 +1,5 @@
+RSpec.describe ReferentialSuite, type: :model do
+ it { should belong_to(:new).class_name('Referential') }
+ it { should belong_to(:current).class_name('Referential') }
+ it { should have_many(:referentials) }
+end