diff options
63 files changed, 301 insertions, 163 deletions
diff --git a/app/assets/stylesheets/components/_pagination.sass b/app/assets/stylesheets/components/_pagination.sass index 88ba61c3c..b811a559c 100644 --- a/app/assets/stylesheets/components/_pagination.sass +++ b/app/assets/stylesheets/components/_pagination.sass @@ -7,6 +7,9 @@ border-radius: 0 line-height: 34px + &:first-letter + text-transform: capitalize + .page_links display: inline-block vertical-align: top diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c4961123d..9a83394e2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -36,12 +36,6 @@ class ApplicationController < ActionController::Base end helper_method :current_organisation - def current_functional_scope - functional_scope = current_organisation.sso_attributes.try(:[], "functional_scope") if current_organisation - JSON.parse(functional_scope) if functional_scope - end - helper_method :current_functional_scope - def collection_name self.class.name.split("::").last.gsub('Controller', '').underscore end diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb index 3d88e4910..adb3b4764 100644 --- a/app/controllers/calendars_controller.rb +++ b/app/controllers/calendars_controller.rb @@ -104,6 +104,10 @@ class CalendarsController < ChouetteController end end + def begin_of_association_chain + current_organisation + end + def ransack_contains_date date =[] if params[:q] && !params[:q]['contains_date(1i)'].empty? diff --git a/app/controllers/compliance_controls_controller.rb b/app/controllers/compliance_controls_controller.rb index 73dc18f59..7df922d01 100644 --- a/app/controllers/compliance_controls_controller.rb +++ b/app/controllers/compliance_controls_controller.rb @@ -5,7 +5,7 @@ class ComplianceControlsController < ChouetteController actions :all, :except => [:index] def select_type - @sti_subclasses = ComplianceControl.subclasses + @sti_subclasses = ComplianceControl.subclasses.sort_by {|compliance_control| compliance_control.default_code} end def show diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index 6e3694547..fe661651e 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -143,7 +143,7 @@ class ReferentialsController < ChouetteController def build_referential if params[:from] source_referential = Referential.find(params[:from]) - @referential = Referential.new_from(source_referential, current_functional_scope) + @referential = Referential.new_from(source_referential, current_organisation) end @referential.data_format = current_organisation.data_format diff --git a/app/javascript/journey_patterns/components/ConfirmModal.js b/app/javascript/journey_patterns/components/ConfirmModal.js index ccd0a9384..fdf32649f 100644 --- a/app/javascript/journey_patterns/components/ConfirmModal.js +++ b/app/javascript/journey_patterns/components/ConfirmModal.js @@ -9,11 +9,11 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Confirmation</h4> + <h4 className='modal-title'>{I18n.t('journey_patterns.show.confirmation')}</h4> </div> <div className='modal-body'> <div className='mt-md mb-md'> - <p>Vous vous apprêtez à changer de page. Voulez-vous valider vos modifications avant cela ?</p> + <p>{I18n.t('journey_patterns.show.confirm_page_change')}</p> </div> </div> <div className='modal-footer'> @@ -23,7 +23,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan type='button' onClick={() => { onModalCancel(modal.confirmModal.callback) }} > - Ne pas valider + {I18n.t('cancel')} </button> <button className='btn btn-primary' @@ -31,7 +31,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan type='button' onClick={() => { onModalAccept(modal.confirmModal.callback, journeyPatterns) }} > - Valider + {I18n.t('actions.submit')} </button> </div> </div> diff --git a/app/javascript/journey_patterns/components/CreateModal.js b/app/javascript/journey_patterns/components/CreateModal.js index a6c1b608a..36b5740dc 100644 --- a/app/javascript/journey_patterns/components/CreateModal.js +++ b/app/javascript/journey_patterns/components/CreateModal.js @@ -38,14 +38,14 @@ export default class CreateModal extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Ajouter une mission</h4> + <h4 className='modal-title'>{I18n.t('journey_patterns.actions.new')}</h4> </div> {(this.props.modal.type == 'create') && ( <form> <div className='modal-body'> <div className='form-group'> - <label className='control-label is-required'>Nom</label> + <label className='control-label is-required'>{I18n.attribute_name('journey_pattern', 'name')}</label> <input type='text' ref='name' @@ -57,7 +57,7 @@ export default class CreateModal extends Component { <div className='row'> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> <div className='form-group'> - <label className='control-label is-required'>Nom public</label> + <label className='control-label is-required'>{I18n.attribute_name('journey_pattern', 'published_name')}c</label> <input type='text' ref='published_name' @@ -69,7 +69,7 @@ export default class CreateModal extends Component { </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> <div className='form-group'> - <label className='control-label'>Code mission</label> + <label className='control-label'>{I18n.attribute_name('journey_pattern', 'registration_number')}</label> <input type='text' ref='registration_number' @@ -87,14 +87,14 @@ export default class CreateModal extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> </form> diff --git a/app/javascript/journey_patterns/components/EditModal.js b/app/javascript/journey_patterns/components/EditModal.js index c960cb41c..1960849fb 100644 --- a/app/javascript/journey_patterns/components/EditModal.js +++ b/app/javascript/journey_patterns/components/EditModal.js @@ -18,12 +18,12 @@ export default class EditModal extends Component { if (this.props.editMode) { return ( <h4 className='modal-title'> - Editer la mission + {I18n.t('journey_patterns.actions.edit')} {this.props.modal.type == 'edit' && <em> "{this.props.modal.modalProps.journeyPattern.name}"</em>} </h4> ) } else { - return <h4 className='modal-title'> Informations </h4> + return <h4 className='modal-title'> {I18n.t('journey_patterns.show.informations')} </h4> } } @@ -41,7 +41,7 @@ export default class EditModal extends Component { <form> <div className='modal-body'> <div className='form-group'> - <label className='control-label is-required'>Nom</label> + <label className='control-label is-required'>{I18n.attribute_name('journey_pattern', 'name')}</label> <input type='text' ref='name' @@ -57,7 +57,7 @@ export default class EditModal extends Component { <div className='row'> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> <div className='form-group'> - <label className='control-label is-required'>Nom public</label> + <label className='control-label is-required'>{I18n.attribute_name('journey_pattern', 'published_name')}</label> <input type='text' ref='published_name' @@ -72,7 +72,7 @@ export default class EditModal extends Component { </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-6'> <div className='form-group'> - <label className='control-label'>Code mission</label> + <label className='control-label'>{I18n.attribute_name('journey_pattern', 'registration_number')}</label> <input type='text' ref='registration_number' @@ -86,7 +86,7 @@ export default class EditModal extends Component { </div> </div> <div> - <label className='control-label'>Signature métier</label> + <label className='control-label'>{I18n.attribute_name('journey_pattern', 'checksum')}</label> <input type='text' ref='checksum' @@ -105,14 +105,14 @@ export default class EditModal extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> } diff --git a/app/javascript/journey_patterns/components/JourneyPattern.js b/app/javascript/journey_patterns/components/JourneyPattern.js index 00b5497f7..d381b0d50 100644 --- a/app/javascript/journey_patterns/components/JourneyPattern.js +++ b/app/javascript/journey_patterns/components/JourneyPattern.js @@ -23,7 +23,7 @@ export default class JourneyPattern extends Component{ let vjURL = routeURL + '/vehicle_journeys?jp=' + jpOid return ( - <a href={vjURL}>Horaires des courses</a> + <a href={vjURL}>{I18n.t('journey_patterns.journey_pattern.vehicle_journey_at_stops')}</a> ) } @@ -139,7 +139,7 @@ export default class JourneyPattern extends Component{ <div className='th'> <div className='strong mb-xs'>{this.props.value.object_id ? this.props.value.short_id : '-'}</div> <div>{this.props.value.registration_number}</div> - <div>{actions.getChecked(this.props.value.stop_points).length} arrêt(s)</div> + <div>{I18n.t('journey_patterns.show.stop_points_count', {count: actions.getChecked(this.props.value.stop_points).length})}</div> {this.hasFeature('costs_in_journey_patterns') && <div className="small row totals"> <span className="col-md-6"><i className="fa fa-arrows-h"></i>{totalDistance}</span> @@ -167,7 +167,7 @@ export default class JourneyPattern extends Component{ data-toggle='modal' data-target='#JourneyPatternModal' > - {this.props.editMode ? 'Editer' : 'Consulter'} + {this.props.editMode ? I18n.t('actions.edit') : I18n.t('actions.show')} </button> </li> <li className={this.props.value.object_id ? '' : 'disabled'}> @@ -183,7 +183,7 @@ export default class JourneyPattern extends Component{ this.props.onDeleteJourneyPattern(this.props.index)} } > - <span className='fa fa-trash'></span>Supprimer + <span className='fa fa-trash'></span>{I18n.t('actions.destroy')} </button> </li> </ul> diff --git a/app/javascript/journey_patterns/components/JourneyPatterns.js b/app/javascript/journey_patterns/components/JourneyPatterns.js index 930acb390..91c783189 100644 --- a/app/javascript/journey_patterns/components/JourneyPatterns.js +++ b/app/javascript/journey_patterns/components/JourneyPatterns.js @@ -84,14 +84,14 @@ export default class JourneyPatterns extends Component { <div className='col-lg-12'> {(this.props.status.fetchSuccess == false) && ( <div className="alert alert-danger mt-sm"> - <strong>Erreur : </strong> - la récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème + <strong>{I18n.t('error')} : </strong> + {I18n.t('journeys_patterns.journey_pattern.fetching_error')} </div> )} { _.some(this.props.journeyPatterns, 'errors') && ( <div className="alert alert-danger mt-sm"> - <strong>Erreur : </strong> + <strong> {I18n.t('error')} : </strong> {this.props.journeyPatterns.map((jp, index) => jp.errors && jp.errors.map((err, i) => { return ( @@ -107,9 +107,9 @@ export default class JourneyPatterns extends Component { <div className={'table table-2entries mt-sm mb-sm' + ((this.props.journeyPatterns.length > 0) ? '' : ' no_result')}> <div className='t2e-head w20'> <div className='th'> - <div className='strong mb-xs'>ID Mission</div> - <div>Code mission</div> - <div>Nb arrêts</div> + <div className='strong mb-xs'>{I18n.t('objectid')}</div> + <div>{I18n.attribute_name('journey_pattern', 'registration_number')}</div> + <div>{I18n.attribute_name('journey_pattern', 'stop_points')}</div> { this.hasFeature('costs_in_journey_patterns') && <div> <div>{I18n.attribute_name('journey_pattern', 'full_journey_time')}</div> diff --git a/app/javascript/journey_patterns/components/Navigate.js b/app/javascript/journey_patterns/components/Navigate.js index 78f324a7d..9e454da5e 100644 --- a/app/javascript/journey_patterns/components/Navigate.js +++ b/app/javascript/journey_patterns/components/Navigate.js @@ -1,5 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import capitalize from 'lodash/capitalize' import actions from '../actions' export default function Navigate({ dispatch, journeyPatterns, pagination, status }) { @@ -17,7 +18,7 @@ export default function Navigate({ dispatch, journeyPatterns, pagination, status <div className='row'> <div className='col-lg-12 text-right'> <div className='pagination'> - Liste des missions {firstItemOnPage} à {(lastItemOnPage < pagination.totalCount) ? lastItemOnPage : pagination.totalCount} sur {pagination.totalCount} + {I18n.t('will_paginate.page_entries_info.multi_page', { model: capitalize(I18n.model_name('journey_pattern', { plural: true })), from: firstItemOnPage, to: lastItemOnPage, count: pagination.totalCount})} <form className='page_links' onSubmit={e => { e.preventDefault() }}> diff --git a/app/javascript/vehicle_journeys/components/ConfirmModal.js b/app/javascript/vehicle_journeys/components/ConfirmModal.js index 75e8a3932..330b4e02f 100644 --- a/app/javascript/vehicle_journeys/components/ConfirmModal.js +++ b/app/javascript/vehicle_journeys/components/ConfirmModal.js @@ -16,7 +16,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan type='button' onClick={() => { onModalCancel(modal.confirmModal.callback) }} > - Ne pas valider + {I18n.t('cancel')} </button> <button className='btn btn-danger' @@ -24,7 +24,7 @@ export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCan type='button' onClick={() => { onModalAccept(modal.confirmModal.callback, vehicleJourneys) }} > - Valider + {I18n.t('actions.submit')} </button> </div> </div> diff --git a/app/javascript/vehicle_journeys/components/Navigate.js b/app/javascript/vehicle_journeys/components/Navigate.js index 24843babc..e79823e49 100644 --- a/app/javascript/vehicle_journeys/components/Navigate.js +++ b/app/javascript/vehicle_journeys/components/Navigate.js @@ -1,5 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import capitalize from 'lodash/capitalize' import actions from'../actions' export default function Navigate({ dispatch, vehicleJourneys, pagination, status, filters}) { @@ -17,7 +18,7 @@ export default function Navigate({ dispatch, vehicleJourneys, pagination, status if(status.fetchSuccess == true) { return ( <div className="pagination"> - {I18n.t("vehicle_journeys.vehicle_journeys_matrix.pagination", {minVJ, maxVJ, total:pagination.totalCount})} + {I18n.t('will_paginate.page_entries_info.multi_page', { model: capitalize(I18n.model_name('vehicle_journey', { plural: true })), from: minVJ, to: maxVJ, count: pagination.totalCount })} <form className='page_links' onSubmit={e => {e.preventDefault()}}> <button onClick={e => { diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js index a60429765..f49b51f08 100644 --- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js +++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js @@ -47,7 +47,7 @@ export default class CreateModal extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Ajouter une course</h4> + <h4 className='modal-title'>{I18n.t('vehicle_journeys.actions.new')}</h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -57,7 +57,7 @@ export default class CreateModal extends Component { <div className='row'> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> <div className='form-group'> - <label className='control-label'>Nom de la course</label> + <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'journey_name')}</label> <input type='text' ref='published_journey_name' @@ -68,7 +68,7 @@ export default class CreateModal extends Component { </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> <div className='form-group'> - <label className='control-label'>Nom du transporteur</label> + <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'company_name')}</label> <CompanySelect2 company = {this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company || undefined} onSelect2Company = {(e) => this.props.onSelect2Company(e)} @@ -78,7 +78,7 @@ export default class CreateModal extends Component { </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> <div className='form-group'> - <label className='control-label is-required'>Nom public de la mission</label> + <label className='control-label is-required'>{I18n.attribute_name('vehicle_journey', 'journey_pattern_published_name')}</label> <MissionSelect2 selection={this.props.modal.modalProps} onSelect2JourneyPattern={this.props.onSelect2JourneyPattern} @@ -89,7 +89,7 @@ export default class CreateModal extends Component { </div> <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> <div className='form-group'> - <label className='control-label'>Numéro de train</label> + <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'published_journey_identifier')}</label> <input type='text' ref='published_journey_identifier' @@ -105,7 +105,7 @@ export default class CreateModal extends Component { /> { this.props.modal.modalProps.selectedJPModal && this.props.modal.modalProps.selectedJPModal.full_schedule && <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'> <div className='form-group'> - <label className='control-label'>Heure de départ</label> + <label className='control-label'>{I18n.attribute_name('vehicle_journey', 'start_time')}</label> <div className='input-group time'> <input type='number' @@ -142,14 +142,14 @@ export default class CreateModal extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> </form> diff --git a/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js b/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js index 4815003d3..b1ce3786b 100644 --- a/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/tools/DeleteVehicleJourneys.js @@ -13,7 +13,7 @@ export default function DeleteVehicleJourneys({onDeleteVehicleJourneys, vehicleJ e.preventDefault() onDeleteVehicleJourneys() }} - title='Supprimer' + title={ I18n.t('actions.delete') } > <span className='fa fa-trash'></span> </button> diff --git a/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js index 102a87d85..d7e48bf08 100644 --- a/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/DuplicateVehicleJourney.js @@ -93,7 +93,7 @@ export default class DuplicateVehicleJourney extends Component { <div className='modal-content'> <div className='modal-header'> <h4 className='modal-title'> - Dupliquer { actions.getSelected(this.props.vehicleJourneys).length > 1 ? 'plusieurs courses' : 'une course' } + {I18n.t('vehicle_journeys.vehicle_journeys_matrix.duplicate', { count: actions.getSelected(this.props.vehicleJourneys).length })} </h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -102,7 +102,7 @@ export default class DuplicateVehicleJourney extends Component { <form className='form-horizontal'> <div className='modal-body'> <div className={'form-group ' + (actions.getSelected(this.props.vehicleJourneys).length > 1 ? 'hidden' : '' )}> - <label className='control-label is-required col-sm-8'>Horaire de départ indicatif</label> + <label className='control-label is-required col-sm-8'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.duplicate.start_time')}</label> <span className="col-sm-4"> <span className={'input-group time' + (actions.getSelected(this.props.vehicleJourneys).length > 1 ? ' disabled' : '')}> <input @@ -133,7 +133,7 @@ export default class DuplicateVehicleJourney extends Component { </div> <div className='form-group'> - <label className='control-label is-required col-sm-8'>Nombre de courses à créer et dupliquer</label> + <label className='control-label is-required col-sm-8'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.duplicate.number')}</label> <div className="col-sm-4"> <input type='number' @@ -152,7 +152,7 @@ export default class DuplicateVehicleJourney extends Component { </div> <div className='form-group'> - <label className='control-label is-required col-sm-8'>Décalage à partir duquel on créé les courses</label> + <label className='control-label is-required col-sm-8'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.duplicate.delta')}</label> <span className="col-sm-4"> <input type='number' @@ -178,7 +178,7 @@ export default class DuplicateVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className={'btn btn-primary ' + (this.state.additional_time == 0 && this.state.originalDT.hour == this.state.duplicate_time_hh && this.state.originalDT.minute == this.state.duplicate_time_mm ? 'disabled' : '')} @@ -186,7 +186,7 @@ export default class DuplicateVehicleJourney extends Component { onClick={this.handleSubmit} disabled={this.disableValidateButton()} > - Valider + {I18n.t('actions.submit')} </button> </div> </form> diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js index 795c2ecff..e4e266c79 100644 --- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js @@ -173,14 +173,14 @@ export default class EditVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> } diff --git a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js index 880542216..5d300f70c 100644 --- a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js @@ -43,11 +43,11 @@ export default class NotesEditVehicleJourney extends Component { renderAssociatedFN() { if (this.footnotes().associated.length == 0) { - return <h3>Aucune note associée</h3> + return <h3>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.no_associated_footnotes')}</h3> } else { return ( <div> - <h3>Notes associées :</h3> + <h3>{I18n.t('vehicle_journeys.form.purchase_windows')} :</h3> {this.footnotes().associated.map((lf, i) => <div key={i} @@ -68,13 +68,13 @@ export default class NotesEditVehicleJourney extends Component { } renderToAssociateFN() { - if (window.line_footnotes.length == 0) return <h3>La ligne ne possède pas de notes</h3> + if (window.line_footnotes.length == 0) return <h3>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.no_line_footnotes')}</h3> if (this.footnotes().to_associate.length == 0) return false return ( <div> - <h3 className='mt-lg'>Sélectionnez les notes à associer à cette course :</h3> + <h3 className='mt-lg'>{I18n.t('vehicle_journeys.vehicle_journeys_matrix.select_footnotes')} :</h3> {this.footnotes().to_associate.map((lf, i) => <div key={i} className='panel panel-default'> <div className='panel-heading'> @@ -111,7 +111,7 @@ export default class NotesEditVehicleJourney extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Notes</h4> + <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.footnotes')}</h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -130,14 +130,14 @@ export default class NotesEditVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> } diff --git a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js index ce9a4cde9..30c511302 100644 --- a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js @@ -44,7 +44,7 @@ export default class PurchaseWindowsEditVehicleJourney extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Calendriers commerciaux associés</h4> + <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.purchase_windows')}s</h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -58,7 +58,7 @@ export default class PurchaseWindowsEditVehicleJourney extends Component { <div className='wrapper'> <div> <div className='form-group'> - <label className='control-label'>{this.props.modal.modalProps.purchase_windows.length == 0 ? "Aucun calendrier commercial associé" : "Calendriers commerciaux associés"}</label> + <label className='control-label'>{this.props.modal.modalProps.purchase_windows.length == 0 ? I18n.t('vehicle_journeys.vehicle_journeys_matrix.no_associated_purchase_windows') : I18n.t('vehicle_journeys.form.purchase_windows')}</label> </div> </div> <div></div> @@ -117,14 +117,14 @@ export default class PurchaseWindowsEditVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit} > - Valider + {I18n.t('actions.submit')} </button> </div> } diff --git a/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js index 6574bfa2d..bc3d8db34 100644 --- a/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/ShiftVehicleJourney.js @@ -27,6 +27,7 @@ export default class ShiftVehicleJourney extends Component { } render() { + let id = this.props.modal.type == 'shift' && actions.getSelected(this.props.vehicleJourneys)[0].short_id if(this.props.status.isFetching == true) { return false } @@ -48,10 +49,7 @@ export default class ShiftVehicleJourney extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Mettre à jour une course</h4> - {(this.props.modal.type == 'shift') && ( - <em>Mettre à jour les horaires de la course {actions.getSelected(this.props.vehicleJourneys)[0].short_id}</em> - )} + <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.slide_title', {id: id})}</h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -61,7 +59,7 @@ export default class ShiftVehicleJourney extends Component { <div className='row'> <div className='col-lg-4 col-lg-offset-4 col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-4 col-xs-12'> <div className='form-group'> - <label className='control-label is-required'>Avec un décalage de</label> + <label className='control-label is-required'>{I18n.t('vehicle_journeys.form.slide_delta')}</label> <input type='number' style={{'width': 104}} @@ -85,14 +83,14 @@ export default class ShiftVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className={'btn btn-primary ' + (this.state.additional_time == 0 ? 'disabled' : '')} type='button' onClick={this.handleSubmit.bind(this)} > - Valider + {I18n.t('actions.submit')} </button> </div> </form> diff --git a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js index f21480563..7a2686c13 100644 --- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js @@ -44,7 +44,7 @@ export default class TimetablesEditVehicleJourney extends Component { <div className='modal-dialog'> <div className='modal-content'> <div className='modal-header'> - <h4 className='modal-title'>Calendriers associés</h4> + <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.time_tables')}</h4> <span type="button" className="close modal-close" data-dismiss="modal">×</span> </div> @@ -58,7 +58,7 @@ export default class TimetablesEditVehicleJourney extends Component { <div className='wrapper'> <div> <div className='form-group'> - <label className='control-label'>{this.props.modal.modalProps.timetables.length == 0 ? "Aucun calendrier associé" : "Calendriers associés"}</label> + <label className='control-label'>{this.props.modal.modalProps.timetables.length == 0 ? I18n.t('vehicle_journeys.vehicle_journeys_matrix.no_associated_timetables'): I18n.t('vehicle_journeys.form.timetables')}</label> </div> </div> <div></div> @@ -119,14 +119,14 @@ export default class TimetablesEditVehicleJourney extends Component { type='button' onClick={this.props.onModalClose} > - Annuler + {I18n.t('cancel')} </button> <button className='btn btn-primary' type='button' onClick={this.handleSubmit} > - Valider + {I18n.t('actions.submit')} </button> </div> } diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js index 5c7f75d99..b7e9691c1 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js @@ -16,6 +16,7 @@ export default class BSelect4 extends Component { } render() { + let placeHolder = I18n.t('') return ( <Select2 data={(this.props.company) ? [this.props.company.name] : undefined} @@ -29,7 +30,7 @@ export default class BSelect4 extends Component { allowClear: true, theme: 'bootstrap', width: '100%', - placeholder: 'Filtrer par transporteur...', + placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.affect_company'), language: require('./fr'), ajax: { url: origin + path + '/companies.json' + '?line_id=' + line, diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js index 72dbd0152..96b34125d 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js @@ -74,7 +74,7 @@ export default class BSelect4 extends Component { width: '100%', escapeMarkup: function (markup) { return markup; }, templateResult: formatRepo, - placeholder: 'Filtrer par code, nom ou OID de mission...', + placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.journey_pattern'), language: require('./fr'), allowClear: false, escapeMarkup: function (markup) { return markup; }, diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js index 0339455ca..9a345b464 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js @@ -26,7 +26,7 @@ export default class BSelect4 extends Component { allowClear: false, theme: 'bootstrap', width: '100%', - placeholder: 'Filtrer par calendrier...', + placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.timetable'), language: require('./fr'), ajax: { url: origin + path + this.props.chunkURL, diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js index ccb4c9595..f5881cef7 100644 --- a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js +++ b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js @@ -25,7 +25,7 @@ export default class BSelect4b extends Component { options={{ allowClear: false, theme: 'bootstrap', - placeholder: 'Filtrer par ID course...', + placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.id'), width: '100%', language: require('./fr'), ajax: { diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb index ae7c25377..c8a02da1f 100644 --- a/app/models/chouette/line.rb +++ b/app/models/chouette/line.rb @@ -51,6 +51,14 @@ module Chouette ) } + scope :for_organisation, ->(organisation){ + if objectids = organisation&.lines_scope + where(objectid: objectids) + else + all + end + } + def self.nullable_attributes [:published_name, :number, :comment, :url, :color, :text_color, :stable_id] end diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb index 537343005..1cc06f927 100644 --- a/app/models/compliance_control.rb +++ b/app/models/compliance_control.rb @@ -76,6 +76,7 @@ require_dependency 'generic_attribute_control/uniqueness' require_dependency 'journey_pattern_control/duplicates' require_dependency 'journey_pattern_control/vehicle_journey' require_dependency 'line_control/route' +require_dependency 'line_control/lines_scope' require_dependency 'route_control/duplicates' require_dependency 'route_control/journey_pattern' require_dependency 'route_control/minimum_length' diff --git a/app/models/line_control/lines_scope.rb b/app/models/line_control/lines_scope.rb new file mode 100644 index 000000000..4210a10dd --- /dev/null +++ b/app/models/line_control/lines_scope.rb @@ -0,0 +1,8 @@ +module LineControl + class LinesScope < ComplianceControl + + def self.default_code; "3-Line-2" end + + def prerequisite; I18n.t("compliance_controls.#{self.class.name.underscore}.prerequisite") end + end +end diff --git a/app/models/line_referential.rb b/app/models/line_referential.rb index 0d2ed39b1..89700c06f 100644 --- a/app/models/line_referential.rb +++ b/app/models/line_referential.rb @@ -1,7 +1,7 @@ class LineReferential < ActiveRecord::Base include ObjectidFormatterSupport extend StifTransportModeEnumerations - + has_many :line_referential_memberships has_many :organisations, through: :line_referential_memberships has_many :lines, class_name: 'Chouette::Line' @@ -14,7 +14,7 @@ class LineReferential < ActiveRecord::Base def add_member(organisation, options = {}) attributes = options.merge organisation: organisation - line_referential_memberships.build attributes + line_referential_memberships.build attributes unless organisations.include?(organisation) end validates :name, presence: true diff --git a/app/models/line_referential_membership.rb b/app/models/line_referential_membership.rb index b49d1b5b1..dcada25bf 100644 --- a/app/models/line_referential_membership.rb +++ b/app/models/line_referential_membership.rb @@ -1,4 +1,6 @@ class LineReferentialMembership < ActiveRecord::Base belongs_to :organisation belongs_to :line_referential + + validates :organisation_id, presence: true, uniqueness: { scope: :line_referential } end diff --git a/app/models/organisation.rb b/app/models/organisation.rb index 745bc0d22..5bef67941 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -86,4 +86,8 @@ class Organisation < ActiveRecord::Base workbenches.default end + def lines_scope + functional_scope = sso_attributes.try(:[], "functional_scope") + JSON.parse(functional_scope) if functional_scope + end end diff --git a/app/models/referential.rb b/app/models/referential.rb index 91a88d02d..0e48be43f 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -233,7 +233,7 @@ class Referential < ActiveRecord::Base end end - def self.new_from(from, functional_scope) + def self.new_from(from, organisation) Referential.new( name: I18n.t("activerecord.copy", name: from.name), slug: "#{from.slug}_clone", @@ -244,7 +244,7 @@ class Referential < ActiveRecord::Base stop_area_referential: from.stop_area_referential, created_from: from, objectid_format: from.objectid_format, - metadatas: from.metadatas.map { |m| ReferentialMetadata.new_from(m, functional_scope) } + metadatas: from.metadatas.map { |m| ReferentialMetadata.new_from(m, organisation) } ) end diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb index 393dc70d3..017eb1449 100644 --- a/app/models/referential_metadata.rb +++ b/app/models/referential_metadata.rb @@ -155,10 +155,10 @@ class ReferentialMetadata < ActiveRecord::Base end private :clear_periods - def self.new_from(from, functional_scope) + def self.new_from(from, organisation) from.dup.tap do |metadata| metadata.referential_source_id = from.referential_id - metadata.line_ids = from.referential.lines.where(id: metadata.line_ids, objectid: functional_scope).collect(&:id) + metadata.line_ids = from.referential.lines.where(id: metadata.line_ids).for_organisation(organisation).pluck(:id) metadata.referential_id = nil end end diff --git a/app/models/simple_exporter.rb b/app/models/simple_exporter.rb index c267b5b8c..1fcb76a29 100644 --- a/app/models/simple_exporter.rb +++ b/app/models/simple_exporter.rb @@ -64,7 +64,7 @@ class SimpleExporter < SimpleInterface def map_item_to_rows item return [item] unless configuration.item_to_rows_mapping - configuration.item_to_rows_mapping.call(item).map {|row| row.is_a?(ActiveRecord::Base) ? row : CustomRow.new(row) } + instance_exec(item, &configuration.item_to_rows_mapping).map {|row| row.is_a?(ActiveRecord::Base) ? row : CustomRow.new(row) } end def resolve_value item, col diff --git a/app/models/stop_area_referential.rb b/app/models/stop_area_referential.rb index a9d3cc9b1..4706cdd77 100644 --- a/app/models/stop_area_referential.rb +++ b/app/models/stop_area_referential.rb @@ -12,7 +12,7 @@ class StopAreaReferential < ActiveRecord::Base def add_member(organisation, options = {}) attributes = options.merge organisation: organisation - stop_area_referential_memberships.build attributes + stop_area_referential_memberships.build attributes unless organisations.include?(organisation) end def last_sync diff --git a/app/models/stop_area_referential_membership.rb b/app/models/stop_area_referential_membership.rb index 435970961..fbed1c004 100644 --- a/app/models/stop_area_referential_membership.rb +++ b/app/models/stop_area_referential_membership.rb @@ -1,4 +1,6 @@ class StopAreaReferentialMembership < ActiveRecord::Base belongs_to :organisation belongs_to :stop_area_referential + + validates :organisation_id, presence: true, uniqueness: { scope: :stop_area_referential } end diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim index 2f0791f50..e1be3df4a 100644 --- a/app/views/dashboards/_dashboard.html.slim +++ b/app/views/dashboards/_dashboard.html.slim @@ -5,7 +5,7 @@ .panel-heading h3.panel-title.with_actions div - = link_to workbench.name, workbench_path(workbench) + = link_to t('dashboards.workbench.title', organisation: workbench.organisation.name), workbench_path(workbench) span.badge.ml-xs = workbench.referentials.count if workbench.referentials.present? div @@ -23,6 +23,7 @@ .panel-heading h3.panel-title.with_actions = link_to I18n.t("activerecord.models.calendar", count: workbench.calendars.size), workgroup_calendars_path(workbench.workgroup) + span.badge.ml-xs = workbench.calendars.count if workbench.calendars.present? div = link_to '', workgroup_calendars_path(workbench.workgroup), class: ' fa fa-chevron-right pull-right' - if workbench.calendars.present? @@ -39,7 +40,7 @@ - @dashboard.current_organisation.stop_area_referentials.each do |referential| .panel-heading h3.panel-title - = referential.name + = t('dashboards.stop_area_referentials.title') .list-group = link_to Chouette::StopArea.model_name.human.pluralize.capitalize, stop_area_referential_stop_areas_path(referential), class: 'list-group-item' @@ -47,7 +48,7 @@ - @dashboard.current_organisation.line_referentials.all.each do |referential| .panel-heading h3.panel-title - = referential.name + = t('dashboards.line_referentials.title') .list-group = link_to Chouette::Line.model_name.human.pluralize.capitalize, line_referential_lines_path(referential), class: 'list-group-item' = link_to Chouette::Company.model_name.human.pluralize.capitalize, line_referential_companies_path(referential), class: 'list-group-item' diff --git a/app/views/layouts/navigation/_nav_panel_operations.html.slim b/app/views/layouts/navigation/_nav_panel_operations.html.slim index 8dce829cd..1c5a1f14b 100644 --- a/app/views/layouts/navigation/_nav_panel_operations.html.slim +++ b/app/views/layouts/navigation/_nav_panel_operations.html.slim @@ -1,5 +1,5 @@ #operations_panel.nav_panel .panel-title - h2 Opérations + h2 = t('layouts.operations') .panel-body p = "Lorem ipsum dolor sit amet..." diff --git a/app/views/layouts/navigation/_nav_panel_profile.html.slim b/app/views/layouts/navigation/_nav_panel_profile.html.slim index bcbf89e67..b0dee5d53 100644 --- a/app/views/layouts/navigation/_nav_panel_profile.html.slim +++ b/app/views/layouts/navigation/_nav_panel_profile.html.slim @@ -1,6 +1,6 @@ #profile_panel.nav_panel .panel-title - h2 Mon Profil + h2 = t('layouts.user.profile') .panel-body p = current_user.name p = current_organisation.name diff --git a/app/views/referentials/_form.html.slim b/app/views/referentials/_form.html.slim index 96d847ec1..c378f871e 100644 --- a/app/views/referentials/_form.html.slim +++ b/app/views/referentials/_form.html.slim @@ -49,7 +49,7 @@ .separator .row .col-lg-11 - = subform.input :lines, as: :select, collection: Chouette::Line.includes(:company).order(:name).where(objectid: current_functional_scope), selected: subform.object.line_ids, label_method: :display_name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': t('simple_form.labels.referential.placeholders.select_lines'), 'multiple': 'multiple', style: 'width: 100%' } + = subform.input :lines, as: :select, collection: Chouette::Line.includes(:company).order(:name).for_organisation(current_organisation), selected: subform.object.line_ids, label_method: :display_name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': t('simple_form.labels.referential.placeholders.select_lines'), 'multiple': 'multiple', style: 'width: 100%' } .col-lg-1 a.clear-lines.btn.btn-default href='#' .fa.fa-trash diff --git a/app/views/stif/dashboards/_dashboard.html.slim b/app/views/stif/dashboards/_dashboard.html.slim index e0f754fd4..7538c7fc7 100644 --- a/app/views/stif/dashboards/_dashboard.html.slim +++ b/app/views/stif/dashboards/_dashboard.html.slim @@ -1,8 +1,4 @@ .row - .col-lg-12 - h2.content_header = t('.subtitle') - -.row .col-lg-6.col-md-6.col-sm-6.col-xs-12 .panel.panel-default .panel-heading diff --git a/config/locales/compliance_check_messages.en.yml b/config/locales/compliance_check_messages.en.yml index 216a363a3..88841f308 100644 --- a/config/locales/compliance_check_messages.en.yml +++ b/config/locales/compliance_check_messages.en.yml @@ -22,10 +22,11 @@ en: 3_routingconstraint_2: "The Routing Constraint Zone %{source_objectid} covers all the stop points of its related route : %{target_0_objectid}." 3_routingconstraint_3: "The Routing Constraint Zone %{source_objectid} has less than 2 stop points" 3_line_1: "On line :%{source_label} (%{source_objectid}), no route has an opposite route" + 3_line_2: "The line %{source_label} (%{source_objectid}) is not in the lines scope of the organization %{reference_value}" 3_generic_1: "%{source_objectid} : the %{source_attribute} attribute value (%{error_value}) does not respect the following pattern : %{reference_value}" 3_generic_2_1: "%{source_objectid} : the %{source_attribute} attributes's value (%{error_value}) is greater than the authorized maximum value : %{reference_value}" 3_generic_2_2: "%{source_objectid} : the %{source_attribute} attributes's value (%{error_value}) is smaller than the authorized minimum value %{reference_value}" 3_generic_3: "%{source_objectid} : the %{source_attribute} attribute (%{error_value}) has a value shared with : %{target_0_objectid}" 3_shape_1: "Tracé %{source_objectid} : le tracé passe trop loin de l'arrêt %{target_0_label} (%{target_0_objectid}) : %{error_value} > %{reference_value}" 3_shape_2: "Tracé %{source_objectid} : le tracé n'est pas défini entre les arrêts %{target_0_label} (%{target_0_objectid}) et %{target_1_label} (%{target_1_objectid})" - 3_shape_3: "Le tracé de l'itinéraire %{source_objectid} est en écart avec la voirie sur %{error_value} sections"
\ No newline at end of file + 3_shape_3: "Le tracé de l'itinéraire %{source_objectid} est en écart avec la voirie sur %{error_value} sections" diff --git a/config/locales/compliance_check_messages.fr.yml b/config/locales/compliance_check_messages.fr.yml index db127d236..167ef411a 100644 --- a/config/locales/compliance_check_messages.fr.yml +++ b/config/locales/compliance_check_messages.fr.yml @@ -22,10 +22,11 @@ fr: 3_routingconstraint_2: "L'ITL %{source_objectid} couvre tous les arrêts de l'itinéraire %{target_0_objectid}." 3_routingconstraint_3: "L'ITL %{source_objectid} n'a pas suffisament d'arrêts (minimum 2 arrêts requis)" 3_line_1: "Sur la ligne %{source_label} (%{source_objectid}), aucun itinéraire n'a d'itinéraire inverse" + 3_line_2: "La ligne %{source_label} (%{source_objectid}) ne fait pas partie du périmètre de lignes de l'organisation %{reference_value}" 3_generic_1: "%{source_objectid} : l'attribut %{source_attribute} a une valeur %{error_value} qui ne respecte pas le motif %{reference_value}" 3_generic_2_1: "%{source_objectid} : l'attribut %{source_attribute} a une valeur %{error_value} supérieure à la valeur maximale autorisée %{reference_value}" 3_generic_2_2: "%{source_objectid} : l'attribut %{source_attribute} a une valeur %{error_value} inférieure à la valeur minimale autorisée %{reference_value}" 3_generic_3: "%{source_objectid} : l'attribut %{source_attribute} a une valeur %{error_value} partagée avec %{target_0_objectid}" 3_shape_1: "Tracé %{source_objectid} : le tracé passe trop loin de l'arrêt %{target_0_label} (%{target_0_objectid}) : %{error_value} > %{reference_value}" 3_shape_2: "Tracé %{source_objectid} : le tracé n'est pas défini entre les arrêts %{target_0_label} (%{target_0_objectid}) et %{target_1_label} (%{target_1_objectid})" - 3_shape_3: "Le tracé de l'itinéraire %{source_objectid} est en écart avec la voirie sur %{error_value} sections"
\ No newline at end of file + 3_shape_3: "Le tracé de l'itinéraire %{source_objectid} est en écart avec la voirie sur %{error_value} sections" diff --git a/config/locales/compliance_controls.en.yml b/config/locales/compliance_controls.en.yml index d8dc44ecc..18069f2f7 100644 --- a/config/locales/compliance_controls.en.yml +++ b/config/locales/compliance_controls.en.yml @@ -142,6 +142,11 @@ en: 3_line_1: "On line :%{source_label} (%{source_objectid}), no route has an opposite route" description: "The routes of a line must have an opposite route" prerequisite: Line has multiple routes + line_control/lines_scope: + messages: + 3_line_2: "The line %{source_label} (%{source_objectid}) is not in the lines scope of the organization %{reference_value}" + description: "The line must be included in the lines scope of the organization" + prerequisite: "None" generic_attribute_control/pattern: messages: 3_generic_1: "%{source_objectid} : the %{source_attribute} attribute value (%{error_value}) does not respect the following pattern : %{reference_value}" @@ -209,6 +214,8 @@ en: one: "Unactivated stop points" line_control/route: one: "The routes of a line must have an opposite route" + line_control/lines_scope: + one: "Lines must be included in the lines scope of the organization" generic_attribute_control/pattern: one: "Attribute pattern of an object in a line" generic_attribute_control/min_max: diff --git a/config/locales/compliance_controls.fr.yml b/config/locales/compliance_controls.fr.yml index 78b92451f..7dc6eeeb3 100644 --- a/config/locales/compliance_controls.fr.yml +++ b/config/locales/compliance_controls.fr.yml @@ -139,6 +139,11 @@ fr: 3_line_1: "Sur la ligne %{source_label} (%{source_objectid}), aucun itinéraire n'a d'itinéraire inverse" description: "Les itinéraires d'une ligne doivent être associés en aller/retour" prerequisite: Ligne disposant de plusieurs itinéraires + line_control/lines_scope: + messages: + 3_line_2: "La ligne %{source_label} (%{source_objectid}) ne fait pas partie du périmètre de lignes de l'organisation %{reference_value}" + description: "Les lignes doivent appartenir au périmètre de lignes de l'organisation" + prerequisite: "Aucun" generic_attribute_control/pattern: messages: 3_generic_1: "%{source_objectid} : l'attribut %{source_attribute} a une valeur %{error_value} qui ne respecte pas le motif %{reference_value}" @@ -206,6 +211,8 @@ fr: one: "ITL & arret désactivé" line_control/route: one: "Appariement des itinéraires" + line_control/lines_scope: + one: "Les lignes doivent appartenir au périmètre de lignes de l'organisation" generic_attribute_control/pattern: one: "Contrôle du contenu selon un pattern" generic_attribute_control/min_max: diff --git a/config/locales/dashboard.en.yml b/config/locales/dashboard.en.yml index 8d46ff7aa..361a3cf2b 100644 --- a/config/locales/dashboard.en.yml +++ b/config/locales/dashboard.en.yml @@ -2,6 +2,8 @@ en: dashboards: show: title: "Dashboard %{organisation}" + workbench: + title: Transport offer %{organisation} calendars: title: Calendars none: No calendar created diff --git a/config/locales/dashboard.fr.yml b/config/locales/dashboard.fr.yml index d0aa36d61..1e1c095b1 100644 --- a/config/locales/dashboard.fr.yml +++ b/config/locales/dashboard.fr.yml @@ -2,6 +2,8 @@ fr: dashboards: show: title: "Tableau de bord %{organisation}" + workbench: + title: Offre de transport %{organisation} calendars: title: Modèles de calendrier none: Aucun calendrier défini diff --git a/config/locales/journey_patterns.en.yml b/config/locales/journey_patterns.en.yml index d480e144d..70ae94dd9 100644 --- a/config/locales/journey_patterns.en.yml +++ b/config/locales/journey_patterns.en.yml @@ -1,6 +1,7 @@ en: journey_patterns: journey_pattern: + fetching_error: "There has been a problem fetching the data. Please reload the page to try again." from_to: "From '%{departure}' to '%{arrival}'" stop_count: "%{count}/%{route_count} stops" vehicle_journeys_count: "Vehicle journeys: %{count}" @@ -19,6 +20,13 @@ en: show: title: "Journey Pattern %{journey_pattern}" stop_points: "Stop point on journey pattern list" + stop_points_count: + none: '%{count} stop areas' + one: '%{count} stop area' + other: '%{count} stop areas' + informations: Informations + confirmation: Confimation + confirm_page_change: You are about to change page. Would you like to save your work before that ? index: title: "Journey Patterns of %{route}" form: @@ -50,7 +58,8 @@ en: creator_id: "Created by" full_journey_time: Full journey commercial_journey_time: Commercial journey - + stop_points: Nb stop areas + checksum: Checksum formtastic: titles: journey_pattern: diff --git a/config/locales/journey_patterns.fr.yml b/config/locales/journey_patterns.fr.yml index 32c1f3f97..10653a02d 100644 --- a/config/locales/journey_patterns.fr.yml +++ b/config/locales/journey_patterns.fr.yml @@ -1,6 +1,7 @@ fr: journey_patterns: journey_pattern: + fetching_error: "La récupération des courses a rencontré un problème. Rechargez la page pour tenter de corriger le problème." from_to: "De '%{departure}' à '%{arrival}'" stop_count: "%{count}/%{route_count} arrêts" vehicle_journeys_count: "Courses: %{count}" @@ -19,6 +20,13 @@ fr: show: title: "Mission %{journey_pattern}" stop_points: "Liste des arrêts de la mission" + stop_points_count: + none: '%{count} arrêt' + one: '%{count} arrêt' + other: '%{count} arrêts' + informations: Informations + confirmation: Confimation + confirm_page_change: Vous vous apprêtez à changer de page. Voulez-vous valider vos modifications avant cela ? index: title: "Missions de %{route}" form: @@ -50,6 +58,8 @@ fr: creator_id: "Créé par" full_journey_time: Parcours complet commercial_journey_time: Parcours commercial + stop_points: Nb arrêts + checksum: Signature métier formtastic: titles: journey_pattern: diff --git a/config/locales/layouts.en.yml b/config/locales/layouts.en.yml index debff05e5..d5717b400 100644 --- a/config/locales/layouts.en.yml +++ b/config/locales/layouts.en.yml @@ -3,6 +3,7 @@ en: back_to_dashboard: "Back to Dashboard" help: "Help" home: "Home" + operations: Operations user: profile: "My Profile" sign_out: "Sign out" diff --git a/config/locales/layouts.fr.yml b/config/locales/layouts.fr.yml index 5e835bcf7..17d23c756 100644 --- a/config/locales/layouts.fr.yml +++ b/config/locales/layouts.fr.yml @@ -3,6 +3,7 @@ fr: back_to_dashboard: "Retour au Tableau de Bord" help: "Aide" home: "Accueil" + operations: Opérations user: profile: "Mon Profil" sign_out: "Déconnexion" diff --git a/config/locales/vehicle_journey_exports.en.yml b/config/locales/vehicle_journey_exports.en.yml index 93a782026..4e658353e 100644 --- a/config/locales/vehicle_journey_exports.en.yml +++ b/config/locales/vehicle_journey_exports.en.yml @@ -1,7 +1,7 @@ en: vehicle_journey_exports: new: - title: "Export existing vehicle journey at stops" + title: Vehicle journeys export basename: "vehicle_journeys" label: vehicle_journey_id: "vj id (empty for new vj)" diff --git a/config/locales/vehicle_journeys.en.yml b/config/locales/vehicle_journeys.en.yml index f1ba96dc5..79e805ee8 100644 --- a/config/locales/vehicle_journeys.en.yml +++ b/config/locales/vehicle_journeys.en.yml @@ -1,14 +1,29 @@ en: vehicle_journeys: vehicle_journeys_matrix: + filters: + id: Filter by ID... + timetable: Filter by journey pattern... + timetable: Filter by timetable... cancel_selection: "Cancel Selection" fetching_error: "There has been a problem fetching the data. Please reload the page to try again." line_routes: "Line's routes" modal_confirm: 'Do you want to save mofications before moving on to the next page ?' - pagination: "Schedules %{minVJ} to %{maxVJ} over %{total}" selected_journeys: "%{count} selected journeys" show_purchase_window: 'Show the purchase window' show_timetable: 'Show calendar' + no_associated_timetables: No associated timetables + no_associated_purchase_windows: No associated purchase windows + no_associated_footnotes: No associated footnotes + duplicate: + one: Clone %{count} vehicle journey + other: Clone %{count} vehicle journeys + start_time: Indicative start time + number: Number of vehicle journeys to create and clone + delta: Delta from which vehicle journeys are created + affect_company: Affect company + no_line_footnotes: The line doesn't have any footnotes + select_footnotes: Select footnotes to associate with the vehicle journey vehicle_journey: title_stopless: "Vehicle journey %{name}" title: "Vehicle journey leaving from %{stop} at %{time}" @@ -17,10 +32,10 @@ en: title: "Vehicle journey frequency leaving from %{stop} at %{time}" title_frequency: "Vehicle journey frequency with %{interval}min leaving from %{stop} at %{time_first} to %{time_last}" actions: - index: "Vehicle time's board" - new: "Add a new timed vehicle journey" + index: "Vehicle journeys" + new: "Add a new vehicle journey" new_frequency: "Add a new frequency vehicle journey" - edit: "Edit this timed vehicle journey" + edit: "Edit this vehicle journey" edit_frequency: "Edit this frequency vehicle journey" destroy: "Remove this vehicle journey" destroy_confirm: "Are you sure you want destroy this vehicle journey?" @@ -48,15 +63,18 @@ en: show_journeys_without_schedule: "Show journeys without schedule" slide_arrival: "arrival time at first stop" slide_departure: "departure time at first stop" - slide_title: "Shift all vehicle passing times" + slide_title: "Shift all the vehicle journey passing times : %{id}" slide: "Shift" + slide_delta: "Shift of" starting_stop: "Departure" stop_title: "Stop" submit_frequency_edit: "Edit frequency vehicle journey" submit_frequency: "Create frequency vehicle journey" submit_timed_edit: "Edit vehicle journey" submit_timed: "Create vehicle journey" - time_tables: "Associated calendars to vehicle journey" + time_tables: "Associated timetables" + purchase_windows: Associated purchase windows + footnotes: Associated footnotes to_arrivals: "Copy departures to arrivals" to_departures: "Copy arrivals to departures" to: "at" @@ -102,6 +120,7 @@ en: checksum: "Checksum" comment: "Comments" company: "Company" + company_name: "Company name" created_at: Created at creator_id: "Created by" departure_time: "Departure" @@ -110,9 +129,10 @@ en: footnote_ids: "Footnotes" id: "Journey ID" journey_frequency_ids: "Timeband" - journey_name: "Name of the journey" + journey_name: "Name of the vehicle journey" journey_pattern_id: "Pattern ID" journey_pattern: "Journey Pattern" + journey_pattern_published_name: "Journey Pattern published name" line: "Line" mobility_restricted_suitability: "PRM accessibility" name: "Journey Name" @@ -137,6 +157,7 @@ en: updated_at: Updated at vehicle_journey_at_stop_ids: "Time list" vehicle_type_identifier: "Vehicle Type Identifier" + start_time: Start time errors: models: vehicle_journey: diff --git a/config/locales/vehicle_journeys.fr.yml b/config/locales/vehicle_journeys.fr.yml index d144e580f..4336bc6dc 100644 --- a/config/locales/vehicle_journeys.fr.yml +++ b/config/locales/vehicle_journeys.fr.yml @@ -1,14 +1,29 @@ fr: vehicle_journeys: vehicle_journeys_matrix: + filters: + id: Filtrer par ID course... + journey_pattern: 'Filtrer par code, nom ou OID de mission...' + timetable: Filter by timetable... cancel_selection: "Annuler la sélection" fetching_error: "La récupération des missions a rencontré un problème. Rechargez la page pour tenter de corriger le problème." line_routes: "Séquences d'arrêts de la ligne" modal_confirm: 'Voulez-vous valider vos modifications avant de changer de page?' - pagination: "Liste des horaires %{minVJ} à %{maxVJ} sur %{total}" selected_journeys: "%{count} course(s) sélectionnée(s)" show_purchase_window: 'Voir le calendrier commercial' show_timetable: 'Voir le calendrier' + no_associated_timetables: Aucun calendrier associé + no_associated_purchase_windows: Aucun calendrier commercial associé + no_associated_footnotes: Aucune note associée + duplicate: + one: Dupliquer %{count} course + other: Dupliquer %{count} courses + start_time: Horaire de départ indicatif + number: Nombre de courses à créer et dupliquer + delta: Décalage à partir duquel on créé les courses + affect_company: Indiquez un nom de transporteur... + no_line_footnotes: La ligne ne possède pas de notes + select_footnotes: Sélectionnez les notes à associer à cette course vehicle_journey: title_stopless: "Course %{name}" title: "Course partant de %{stop} à %{time}" @@ -48,8 +63,9 @@ fr: show_journeys_without_schedule: "Afficher les courses sans horaires" slide_arrival: "horaire d'arrivée au 1° arrêt à" slide_departure: "horaire de départ au 1° arrêt à" - slide_title: "Décaler l'ensemble des horaires de course" + slide_title: "Décaler l'ensemble des horaires de la course : %{id}" slide: "Décaler" + slide_delta: "Avec un décalage de" starting_stop: "Origine" stop_title: "Arrêt" submit_frequency_edit: "Editer course en fréquence" @@ -57,6 +73,8 @@ fr: submit_timed_edit: "Editer course" submit_timed: "Créer course" time_tables: "Calendriers associés à la course" + purchase_windows: "Calendriers commerciaux associés à la course" + footnotes: "Notes associés à la course" to_arrivals: "Copie départs vers arrivées" to_arrivals: "Copie départs vers arrivées" to_departures: "Copie arrivées vers départs" @@ -103,6 +121,7 @@ fr: checksum: "Signature métier" comment: "Commentaires" company: "Transporteur" + company|_name: "Nom du transporteur" created_at: "Créé le" creator_id: "Créé par" departure_time: "Départ" @@ -114,6 +133,7 @@ fr: journey_name: "Nom de la course" journey_pattern_id: "ID Mission" journey_pattern: "Mission" + journey_pattern_published_name: "Nom public de la mission" line: "Ligne" mobility_restricted_suitability: "Accessibilité PMR" name: "Nom Course" @@ -129,7 +149,7 @@ fr: route: "Itinéraire" time_slot: "Fréquence" time_table_ids: "Liste des calendriers" - time_tables: "Calendriers" + time_tables: "Calendriers associés" train_number: "Numéro de train" transport_mode: "Mode de transport" transport_submode: "Sous-mode de transport" @@ -138,6 +158,7 @@ fr: updated_at: "Edité le" vehicle_journey_at_stop_ids: "Liste des horaires" vehicle_type_identifier: "Type d'identifiant du véhicule" + start_time: Heure de départ errors: models: vehicle_journey: diff --git a/config/locales/will_paginate.en.yml b/config/locales/will_paginate.en.yml index 29b8fe2bf..8f3189675 100644 --- a/config/locales/will_paginate.en.yml +++ b/config/locales/will_paginate.en.yml @@ -32,11 +32,11 @@ en: single_page: zero: "No item found" one: "1 %{model} shown" - other: "%{model} 1 to %{count} of %{count}" + other: "%{model} 1 to %{count} out of %{count}" single_page_html: zero: "No item found" one: "1 %{model} shown" - other: "%{model} 1 to %{count} of %{count}" + other: "%{model} 1 to %{count} out of %{count}" - multi_page: "%{model} %{from} to %{to} of %{count}" - multi_page_html: "%{model} %{from} to %{to} of %{count}" + multi_page: "%{model} list %{from} to %{to} out of %{count}" + multi_page_html: "%{model} list %{from} to %{to} out of %{count}" diff --git a/db/schema.rb b/db/schema.rb index d90bf7b6c..77e35f449 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -18,7 +18,6 @@ ActiveRecord::Schema.define(version: 20180319043333) do enable_extension "hstore" enable_extension "postgis" enable_extension "unaccent" - enable_extension "objectid" create_table "access_links", id: :bigserial, force: :cascade do |t| t.integer "access_point_id", limit: 8 diff --git a/db/seeds/seed_helpers.rb b/db/seeds/seed_helpers.rb new file mode 100644 index 000000000..8e47e10bd --- /dev/null +++ b/db/seeds/seed_helpers.rb @@ -0,0 +1,12 @@ +class ActiveRecord::Base + def self.seed_by(key_attribute, &block) + model = find_or_create_by! key_attribute + print "Seed #{name} #{key_attribute.inspect} " + yield model + + puts "[#{(model.changed? ? 'updated' : 'no change')}]" + model.save! + + model + end +end diff --git a/db/seeds/stif.seeds.rb b/db/seeds/stif.seeds.rb index aa87b6f6c..bb73b0b9c 100644 --- a/db/seeds/stif.seeds.rb +++ b/db/seeds/stif.seeds.rb @@ -1,46 +1,25 @@ # coding: utf-8 -# This file should contain all the record creation needed to seed the database with its default values. -# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). -stop_area_referential = StopAreaReferential.find_or_create_by!(name: "Reflex", objectid_format: "stif_netex") -line_referential = LineReferential.find_or_create_by!(name: "CodifLigne", objectid_format: "stif_netex") +require_relative 'seed_helpers' -workgroup = Workgroup.find_or_create_by!(name: "Gestion de l'offre théorique IDFm") do |w| - w.line_referential = line_referential - w.stop_area_referential = stop_area_referential - w.export_types = ["Export::Netex"] +stif = Organisation.seed_by(code: "STIF") do |o| + o.name = 'STIF' end -Workbench.update_all workgroup_id: workgroup - -# Organisations -stif = Organisation.find_or_create_by!(code: "STIF") do |org| - org.name = 'STIF' +stop_area_referential = StopAreaReferential.seed_by(name: "Reflex") do |r| + r.objectid_format = "stif_netex" + r.add_member stif, owner: true end -# operator = Organisation.find_or_create_by!(code: 'transporteur-a') do |organisation| -# organisation.name = "Transporteur A" -# end - -# Member -line_referential.add_member stif, owner: true -# line_referential.add_member operator -stop_area_referential.add_member stif, owner: true -# stop_area_referential.add_member operator +line_referential = LineReferential.seed_by(name: "CodifLigne") do |r| + r.objectid_format = "stif_netex" + r.add_member stif, owner: true +end -# Users -# stif.users.find_or_create_by!(username: "admin") do |user| -# user.email = 'stif-boiv@af83.com' -# user.password = "secret" -# user.name = "STIF Administrateur" -# end -# -# operator.users.find_or_create_by!(username: "transporteur") do |user| -# user.email = 'stif-boiv+transporteur@af83.com' -# user.password = "secret" -# user.name = "Martin Lejeune" -# end +workgroup = Workgroup.seed_by(name: "Gestion de l'offre théorique IDFm") do |w| + w.line_referential = line_referential + w.stop_area_referential = stop_area_referential + w.export_types = ["Export::Netex"] +end -# Include all Lines in organisation functional_scope -stif.update sso_attributes: { functional_scope: line_referential.lines.pluck(:objectid) } -#operator.update sso_attributes: { functional_scope: line_referential.lines.limit(3).pluck(:objectid) } +Workbench.update_all workgroup_id: workgroup diff --git a/spec/features/calendars_permissions_spec.rb b/spec/features/calendars_permissions_spec.rb index 4857592d5..656c0dd78 100644 --- a/spec/features/calendars_permissions_spec.rb +++ b/spec/features/calendars_permissions_spec.rb @@ -1,8 +1,8 @@ RSpec.describe 'Calendars', type: :feature do login_user - let(:calendar) { create :calendar, organisation_id: 1 } - let(:workgroup) { calendar.workgroup } + let(:calendar) { create :calendar, organisation: first_organisation, workgroup: first_workgroup } + let(:workgroup) { first_workgroup } describe 'permissions' do before do diff --git a/spec/features/calendars_spec.rb b/spec/features/calendars_spec.rb new file mode 100644 index 000000000..26220746b --- /dev/null +++ b/spec/features/calendars_spec.rb @@ -0,0 +1,16 @@ +RSpec.describe 'Calendars', type: :feature do + login_user + + let(:calendar1) { create(:calendar, workgroup: @user.organisation.workgroups.first, organisation: @user.organisation) } + let(:calendar2) { create(:calendar) } + + describe "index" do + before(:each) do + visit workgroup_calendars_path(calendar1.workgroup) + end + it "should only display calendars from same workgroup" do + expect(page).to have_content calendar1.name + expect(page).to_not have_content calendar2.name + end + end +end
\ No newline at end of file diff --git a/spec/models/referential_metadata_spec.rb b/spec/models/referential_metadata_spec.rb index 291ed974a..88a12b2bb 100644 --- a/spec/models/referential_metadata_spec.rb +++ b/spec/models/referential_metadata_spec.rb @@ -12,14 +12,19 @@ RSpec.describe ReferentialMetadata, :type => :model do describe ".new_from" do let(:referential_metadata) { create :referential_metadata, referential_source: create(:referential) } - let(:new_referential_metadata) { ReferentialMetadata.new_from(referential_metadata, []) } + let(:new_referential_metadata) { ReferentialMetadata.new_from(referential_metadata, nil) } + before do + referential_metadata.line_ids.each do |id| + Chouette::Line.find(id).update_attribute :line_referential_id, referential_metadata.referential.line_referential_id + end + end it "should not have an associated referential" do expect(new_referential_metadata).to be_a_new(ReferentialMetadata) end - xit "should have the same lines" do - expect(new_referential_metadata.lines).to eq(referential_metadata.lines) + it "should have the same lines" do + expect(new_referential_metadata.line_ids.sort).to eq(referential_metadata.line_ids.sort) end it "should have the same periods" do @@ -34,6 +39,14 @@ RSpec.describe ReferentialMetadata, :type => :model do expect(new_referential_metadata.referential_source).to eq(referential_metadata.referential) end + context "with a functional scope" do + let(:organisation){ create :organisation, sso_attributes: {"functional_scope" => [referential_metadata.referential.lines.first.objectid]} } + let(:new_referential_metadata) { ReferentialMetadata.new_from(referential_metadata, organisation) } + + it "should scope the lines" do + expect(new_referential_metadata.line_ids).to eq [referential_metadata.referential.lines.first.id] + end + end end describe "Period" do diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb index 1d9b3d78a..ca2caf57f 100644 --- a/spec/models/referential_spec.rb +++ b/spec/models/referential_spec.rb @@ -55,7 +55,7 @@ describe Referential, :type => :model do context "Cloning referential" do let(:clone) do - Referential.new_from(ref, []) + Referential.new_from(ref, nil) end let!(:workbench){ create :workbench } diff --git a/spec/support/referential.rb b/spec/support/referential.rb index 9acdce73a..b50844ae4 100644 --- a/spec/support/referential.rb +++ b/spec/support/referential.rb @@ -8,6 +8,10 @@ module ReferentialHelper Organisation.find_by!(code: "first") end + def first_workgroup + Workgroup.find_by_name('IDFM') + end + def self.included(base) base.class_eval do extend ClassMethods @@ -53,10 +57,18 @@ RSpec.configure do |config| referential.add_member organisation, owner: true end + workgroup = FactoryGirl.create( + :workgroup, + name: "IDFM", + line_referential: line_referential, + stop_area_referential: stop_area_referential + ) + workbench = FactoryGirl.create( :workbench, name: "Gestion de l'offre", organisation: organisation, + workgroup: workgroup, line_referential: line_referential, stop_area_referential: stop_area_referential ) |
