diff options
46 files changed, 404 insertions, 73 deletions
| diff --git a/app/assets/stylesheets/modules/_jp_collection.sass b/app/assets/stylesheets/modules/_jp_collection.sass index 9d68a217f..b4370a5ac 100644 --- a/app/assets/stylesheets/modules/_jp_collection.sass +++ b/app/assets/stylesheets/modules/_jp_collection.sass @@ -5,7 +5,6 @@  #journey_patterns    .table-2entries      .t2e-head -        > .td          position: relative          padding-left: 25px @@ -119,6 +118,12 @@            .td              padding: 15px 8px +          .totals +            color: $blue +            padding-top: 4px +            i +              padding-right: 3px +            $link-size: 10px            .link              position: absolute diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 474277da1..80d194096 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -41,6 +41,11 @@ class ApplicationController < ActionController::Base    end    helper_method :current_offer_workbench +  def current_workgroup +    current_offer_workbench.workgroup +  end +  helper_method :current_workgroup +    def current_functional_scope      functional_scope = current_organisation.sso_attributes.try(:[], "functional_scope") if current_organisation      JSON.parse(functional_scope) if functional_scope diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb index b37ac6cd0..da567779e 100644 --- a/app/controllers/journey_patterns_collections_controller.rb +++ b/app/controllers/journey_patterns_collections_controller.rb @@ -44,6 +44,7 @@ class JourneyPatternsCollectionsController < ChouetteController              :zip_code => sp.stop_area.try(:zip_code),              :city_name => sp.stop_area.try(:city_name),              :country_name => sp.stop_area.try(:country_name), +            :time_zone_formatted_offset => sp.stop_area.try(:time_zone_formatted_offset),              :comment => sp.stop_area.try(:comment),              :area_type => sp.stop_area.try(:area_type),              :registration_number => sp.stop_area.try(:registration_number), diff --git a/app/controllers/merges_controller.rb b/app/controllers/merges_controller.rb index a95768139..1ce64ed58 100644 --- a/app/controllers/merges_controller.rb +++ b/app/controllers/merges_controller.rb @@ -11,7 +11,7 @@ class MergesController < ChouetteController    private    def set_mergeable_controllers -    @mergeable_referentials ||= parent.referentials.ready.not_in_referential_suite +    @mergeable_referentials ||= parent.referentials.mergeable      Rails.logger.debug "Mergeables: #{@mergeable_referentials.inspect}"    end diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb index e3e067782..eb3367d0c 100644 --- a/app/controllers/vehicle_journeys_controller.rb +++ b/app/controllers/vehicle_journeys_controller.rb @@ -49,6 +49,7 @@ class VehicleJourneysController < ChouetteController        end        format.html do          load_missions +        load_custom_fields          @stop_points_list = []          @stop_points_list = route.stop_points.includes(:stop_area).map do |sp|            { @@ -59,6 +60,7 @@ class VehicleJourneysController < ChouetteController              :for_boarding => sp.try(:for_boarding),              :for_alighting => sp.try(:for_alighting),              :name => sp.stop_area.try(:name), +            :time_zone_formatted_offset => sp.stop_area.try(:time_zone_formatted_offset),              :zip_code => sp.stop_area.try(:zip_code),              :city_name => sp.stop_area.try(:city_name),              :comment => sp.stop_area.try(:comment), @@ -176,6 +178,10 @@ class VehicleJourneysController < ChouetteController    end    private +  def load_custom_fields +    @custom_fields = current_workgroup.custom_fields_definitions +  end +    def load_missions      @all_missions = route.journey_patterns.count > 10 ? [] : route.journey_patterns.map do |item|        { diff --git a/app/decorators/network_decorator.rb b/app/decorators/network_decorator.rb index 1f62fe512..b0a19cf60 100644 --- a/app/decorators/network_decorator.rb +++ b/app/decorators/network_decorator.rb @@ -35,7 +35,7 @@ class NetworkDecorator < Draper::Decorator            object          ),          method: :delete, -        data: { confirm: t('networks.actions.destroy_confirm') } +        data: { confirm: h.t('networks.actions.destroy_confirm') }        )      end diff --git a/app/javascript/helpers/stop_area_header_manager.js b/app/javascript/helpers/stop_area_header_manager.js index 54d957be9..c9f397dee 100644 --- a/app/javascript/helpers/stop_area_header_manager.js +++ b/app/javascript/helpers/stop_area_header_manager.js @@ -21,7 +21,14 @@ export default class StopAreaHeaderManager {          data-headline={showHeadline}          title={sp.city_name + ' (' + sp.zip_code +')'}        > -        <span><span>{sp.name}</span></span> +        <span> +          <span> +            {sp.name} +            {sp.time_zone_formatted_offset && <span className="small"> +               ({sp.time_zone_formatted_offset}) +            </span>} +          </span> +        </span>        </div>      )    } diff --git a/app/javascript/journey_patterns/components/JourneyPattern.js b/app/javascript/journey_patterns/components/JourneyPattern.js index 8dc542bc8..ecbebe2cc 100644 --- a/app/javascript/journey_patterns/components/JourneyPattern.js +++ b/app/javascript/journey_patterns/components/JourneyPattern.js @@ -74,18 +74,60 @@ export default class JourneyPattern extends Component{      return !this.props.status.policy[`journey_patterns.${action}`]    } +  totals(){ +    let totalTime = 0 +    let totalDistance = 0 +    let from = null +    this.props.value.stop_points.map((stopPoint, i) =>{ +      if(from && stopPoint.checked){ +        let [costsKey, costs, time, distance] = this.getTimeAndDistanceBetweenStops(from, stopPoint.id) +        totalTime += time +        totalDistance += distance +      } +      if(stopPoint.checked){ +        from = stopPoint.id +      } +    }) +    return [this.formatTime(totalTime), this.formatDistance(totalDistance)] +  } + +  getTimeAndDistanceBetweenStops(from, to){ +    let costsKey = from + "-" + to +    let costs = this.props.value.costs[costsKey] || {distance: 0, time: 0} +    let time = costs['time'] || 0 +    let distance = costs['distance'] || 0 +    return [costsKey, costs, time, distance] +  } + +  formatDistance(distance){ +    return parseFloat(Math.round(distance * 100) / 100).toFixed(2) + " km" +  } + +  formatTime(time){ +    if(time < 60){ +      return time + " min" +    } +    else{ +      let hours = parseInt(time/60) +      return hours + " h " + (time - 60*hours) + " min" +    } +  } +    render() {      this.previousSpId = undefined +    let [totalTime, totalDistance] = this.totals()      return (        <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record') + (this.props.value.errors ? ' has-error': '') + (this.hasFeature('costs_in_journey_patterns') ? ' with-costs' : '')}> -        {/* Errors */} -        {/* this.props.value.errors ? this.getErrors(this.props.value.errors) : '' */} -          <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> - +          {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> +              <span className="col-md-6"><i className="fa fa-clock-o"></i>{totalTime}</span> +            </div> +          }            <div className={this.props.value.deletable ? 'btn-group disabled' : 'btn-group'}>              <div                className={this.props.value.deletable ? 'btn dropdown-toggle disabled' : 'btn dropdown-toggle'} @@ -132,17 +174,8 @@ export default class JourneyPattern extends Component{              let distance = null              let time_in_words = null              if(this.previousSpId && stopPoint.checked){ -              costsKey = this.previousSpId + "-" + stopPoint.id -              costs = this.props.value.costs[costsKey] || {distance: 0, time: 0} -              time = costs['time'] || 0 -              distance = costs['distance'] || 0 -              if(time < 60){ -                time_in_words = time + " min" -              } -              else{ -                let hours = parseInt(time/60) -                time_in_words = hours + " h " + (time - 60*hours) + " min" -              } +              [costsKey, costs, time, distance] = this.getTimeAndDistanceBetweenStops(this.previousSpId, stopPoint.id) +              time_in_words = this.formatTime(time)              }              if(stopPoint.checked){                this.previousSpId = stopPoint.id @@ -165,7 +198,7 @@ export default class JourneyPattern extends Component{                      </p>                    </div>}                    {!this.props.editMode && <div> -                    <p><i className="fa fa-arrows-h"></i>{(costs['distance'] || 0) + " km"}</p> +                    <p><i className="fa fa-arrows-h"></i>{this.formatDistance(costs['distance'] || 0)}</p>                      <p><i className="fa fa-clock-o"></i>{time_in_words}</p>                    </div>}                  </div>} diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js index ab28371fe..aa5738d59 100644 --- a/app/javascript/packs/vehicle_journeys/index.js +++ b/app/javascript/packs/vehicle_journeys/index.js @@ -71,7 +71,8 @@ var initialState = {      modalProps: {},      confirmModal: {}    }, -  missions: window.all_missions +  missions: window.all_missions, +  custom_fields: window.custom_fields  }  if (window.jpOrigin){ diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js index 07c684760..90328458b 100644 --- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js +++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js @@ -3,15 +3,17 @@ import PropTypes from 'prop-types'  import actions from '../../actions'  import MissionSelect2 from './select2s/MissionSelect2'  import CompanySelect2 from './select2s/CompanySelect2' +import CustomFieldsInputs from './CustomFieldsInputs'  export default class CreateModal extends Component {    constructor(props) {      super(props) +    this.custom_fields = _.assign({}, this.props.custom_fields)    }    handleSubmit() {      if (actions.validateFields(...this.refs, $('.vjCreateSelectJP')[0]) && this.props.modal.modalProps.selectedJPModal) { -      this.props.onAddVehicleJourney(this.refs, this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company) +      this.props.onAddVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company)        this.props.onModalClose()        $('#NewVehicleJourneyModal').modal('hide')      } @@ -89,6 +91,11 @@ export default class CreateModal extends Component {                                  />                              </div>                            </div> +                          <CustomFieldsInputs +                            values={this.props.custom_fields} +                            onUpdate={(code, value) => this.custom_fields[code]["value"] = value} +                            disabled={false} +                          />                            { 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> diff --git a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js new file mode 100644 index 000000000..90d72a801 --- /dev/null +++ b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js @@ -0,0 +1,50 @@ +import _ from 'lodash' +import Select2 from 'react-select2-wrapper' +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +export default class CustomFieldsInputs extends Component { +  constructor(props) { +    super(props) +  } + +  listInput(cf){ +    return( +      <Select2 +        data={_.map(cf.options.list_values, (v, k) => { +          return {id: k, text: (v.length > 0 ? v : '\u00A0')} +        })} +        ref={'custom_fields.' + cf.code} +        className='form-control' +        defaultValue={cf.value} +        disabled={this.props.disabled} +        options={{ +          theme: 'bootstrap', +          width: '100%' +        }} +        onSelect={(e) => this.props.onUpdate(cf.code, e.params.data.id) } +      /> +    ) +  } + +  render() { +    return ( +      <div> +        {_.map(this.props.values, (cf, code) => +          <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12' key={code}> +            <div className='form-group'> +              <label className='control-label'>{cf.name}</label> +              {this[cf.field_type + "Input"](cf)} +            </div> +          </div> +        )} +      </div> +    ) +  } +} + +CustomFieldsInputs.propTypes = { +  onUpdate: PropTypes.func.isRequired, +  values: PropTypes.object.isRequired, +  disabled: PropTypes.bool.isRequired +} diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js index 08d74baba..2893422f8 100644 --- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'  import PropTypes from 'prop-types'  import actions from '../../actions'  import CompanySelect2 from './select2s/CompanySelect2' +import CustomFieldsInputs from './CustomFieldsInputs'  export default class EditVehicleJourney extends Component {    constructor(props) { @@ -15,8 +16,8 @@ export default class EditVehicleJourney extends Component {          company = this.props.modal.modalProps.selectedCompany        } else if (typeof this.props.modal.modalProps.vehicleJourney.company === "object") {          company = this.props.modal.modalProps.vehicleJourney.company -      }  -      this.props.onEditVehicleJourney(this.refs, company) +      } +      this.props.onEditVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), company)        this.props.onModalClose()        $('#EditVehicleJourneyModal').modal('hide')      } @@ -27,6 +28,9 @@ export default class EditVehicleJourney extends Component {        return false      }      if(this.props.status.fetchSuccess == true) { +      if(this.props.modal.modalProps.vehicleJourney){ +        this.custom_fields = _.assign({}, this.props.modal.modalProps.vehicleJourney.custom_fields) +      }        return (          <li className='st_action'>            <button @@ -140,8 +144,15 @@ export default class EditVehicleJourney extends Component {                              defaultValue={this.props.modal.modalProps.vehicleJourney.checksum}                              />                          </div> - +                        <div className='row'> +                          <CustomFieldsInputs +                            values={this.props.modal.modalProps.vehicleJourney.custom_fields} +                            onUpdate={(code, value) => this.custom_fields[code]["value"] = value} +                            disabled={!this.props.editMode} +                          /> +                        </div>                        </div> +                        {                          this.props.editMode &&                          <div className='modal-footer'> diff --git a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js index 0f4a0ea7d..0db7628be 100644 --- a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js +++ b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js @@ -10,6 +10,7 @@ const mapStateToProps = (state, ownProps) => {      status: state.status,      stopPointsList: state.stopPointsList,      missions: state.missions, +    custom_fields: state.custom_fields,    }  } diff --git a/app/javascript/vehicle_journeys/reducers/custom_fields.js b/app/javascript/vehicle_journeys/reducers/custom_fields.js new file mode 100644 index 000000000..482fd91cb --- /dev/null +++ b/app/javascript/vehicle_journeys/reducers/custom_fields.js @@ -0,0 +1,6 @@ +export default function custom_fields(state = [], action) { +  switch (action.type) { +    default: +      return state +  } +} diff --git a/app/javascript/vehicle_journeys/reducers/index.js b/app/javascript/vehicle_journeys/reducers/index.js index 862c864ae..1963f7c6d 100644 --- a/app/javascript/vehicle_journeys/reducers/index.js +++ b/app/javascript/vehicle_journeys/reducers/index.js @@ -7,6 +7,7 @@ import filters from './filters'  import editMode from './editMode'  import stopPointsList from './stopPointsList'  import missions from './missions' +import custom_fields from './custom_fields'  const vehicleJourneysApp = combineReducers({    vehicleJourneys, @@ -16,7 +17,8 @@ const vehicleJourneysApp = combineReducers({    filters,    editMode,    stopPointsList, -  missions +  missions, +  custom_fields  })  export default vehicleJourneysApp diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js index 0549c7adc..62b846d9a 100644 --- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js @@ -54,6 +54,7 @@ const vehicleJourney= (state = {}, action, keep) => {          pristineVjasList.push(newVjas)        }) +        return {          company: action.selectedCompany,          journey_pattern: action.selectedJourneyPattern, @@ -68,7 +69,8 @@ const vehicleJourney= (state = {}, action, keep) => {          selected: false,          deletable: false,          transport_mode: window.transportMode ? window.transportMode : 'undefined', -        transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined' +        transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined', +        custom_fields: action.data.custom_fields        }      case 'DUPLICATE_VEHICLEJOURNEY':      case 'SHIFT_VEHICLEJOURNEY': @@ -148,6 +150,7 @@ export default function vehicleJourneys(state = [], action) {              company: action.selectedCompany,              published_journey_name: action.data.published_journey_name.value,              published_journey_identifier: action.data.published_journey_identifier.value, +            custom_fields: action.data.custom_fields,            })          }else{            return vj diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index 52602be9f..37d20ae02 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -358,11 +358,17 @@ module Chouette        update_attribute :deleted_at, Time.now      end +      def country_name        return unless country_code        country = ISO3166::Country[country_code]        country.translations[I18n.locale.to_s] || country.name      end + +    def time_zone_formatted_offset +      return nil unless time_zone.present? +      ActiveSupport::TimeZone[time_zone]&.formatted_offset +    end    end  end diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 1904e1b92..8a704d8c0 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -132,10 +132,14 @@ module Chouette      def update_vjas_from_state state        state.each do |vjas|          next if vjas["dummy"] +        stop_point = Chouette::StopPoint.find_by(objectid: vjas['stop_point_objectid']) +        stop_area = stop_point&.stop_area +        tz = stop_area&.time_zone +        tz = tz && ActiveSupport::TimeZone[tz]          params = {}.tap do |el|            ['arrival_time', 'departure_time'].each do |field|              time = "#{vjas[field]['hour']}:#{vjas[field]['minute']}" -            el[field.to_sym] = Time.parse("2000-01-01 #{time}:00 UTC") +            el[field.to_sym] = Time.parse("2000-01-01 #{time}:00 #{tz&.formatted_offset || "UTC"}")            end          end          stop = create_or_find_vjas_from_state(vjas) @@ -220,6 +224,7 @@ module Chouette        ['company', 'journey_pattern'].map do |association|          attrs["#{association}_id"] = item[association]['id'] if item[association]        end +      attrs["custom_field_values"] = Hash[*(item["custom_fields"] || {}).map{|k, v| [k, v["value"]]}.flatten]        attrs      end @@ -258,8 +263,15 @@ module Chouette        end      end +    def self.custom_fields +      CustomField.where(resource_type: self.name.split("::").last) +    end + +      def custom_fields -      CustomField.where(resource_type: self.class.name.split("::").last) +      Hash[*self.class.custom_fields.map do |v| +        [v.code, v.slice(:code, :name, :field_type, :options).update(value: custom_field_value(v.code))] +      end.flatten]      end      def custom_field_value key diff --git a/app/models/chouette/vehicle_journey_at_stop.rb b/app/models/chouette/vehicle_journey_at_stop.rb index 6b3c1e7de..f1a3cdcaa 100644 --- a/app/models/chouette/vehicle_journey_at_stop.rb +++ b/app/models/chouette/vehicle_journey_at_stop.rb @@ -77,11 +77,37 @@ module Chouette      end      def departure -      departure_time.utc.strftime "%H:%M" if departure_time +      format_time departure_time.utc      end      def arrival -      arrival_time.utc.strftime "%H:%M" if arrival_time +      format_time arrival_time.utc +    end + +    def departure_local_time +      local_time departure_time +    end + +    def arrival_local_time +      local_time arrival_time +    end + +    def departure_local +      format_time departure_local_time +    end + +    def arrival_local +      format_time arrival_local_time +    end + +    private +    def local_time time +      return time unless stop_point&.stop_area&.time_zone.present? +      time + ActiveSupport::TimeZone[stop_point.stop_area.time_zone].utc_offset +    end + +    def format_time time +      time.strftime "%H:%M" if time      end    end diff --git a/app/models/merge.rb b/app/models/merge.rb index 26bd5398b..eebf1d2e1 100644 --- a/app/models/merge.rb +++ b/app/models/merge.rb @@ -360,6 +360,8 @@ class Merge < ActiveRecord::Base    def save_current      output.update current: new, new: nil      output.current.update referential_suite: output + +    referentials.update_all merged_at: created_at, archived_at: created_at    end    def fixme_functional_scope diff --git a/app/models/referential.rb b/app/models/referential.rb index 718f60ffd..92931564d 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -463,6 +463,18 @@ class Referential < ActiveRecord::Base      not metadatas_overlap?    end +  def merged? +    merged_at.present? +  end + +  def self.not_merged +    where merged_at: nil +  end + +  def self.mergeable +    ready.not_merged.not_in_referential_suite +  end +    private    def lock_table diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb index 995917fac..511bbfeb0 100644 --- a/app/models/workgroup.rb +++ b/app/models/workgroup.rb @@ -11,4 +11,8 @@ class Workgroup < ActiveRecord::Base    validates_presence_of :stop_area_referential_id    has_many :custom_fields + +  def custom_fields_definitions +    Hash[*custom_fields.map{|cf| [cf.code, cf]}.flatten] +  end  end diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index af5c14880..f5c2d7c08 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -18,7 +18,7 @@ class ReferentialPolicy < ApplicationPolicy    end    def clone? -    !referential_read_only? && create? +    !record.in_referential_suite? && create?    end    def validate? @@ -30,7 +30,7 @@ class ReferentialPolicy < ApplicationPolicy    end    def unarchive? -    !record.archived_at.nil? && organisation_match? && user.has_permission?('referentials.update') +    record.archived? && !record.merged? && organisation_match? && user.has_permission?('referentials.update')    end    def common_lines? diff --git a/app/views/autocomplete_stop_areas/around.rabl b/app/views/autocomplete_stop_areas/around.rabl index bc8f06054..d067dc4d0 100644 --- a/app/views/autocomplete_stop_areas/around.rabl +++ b/app/views/autocomplete_stop_areas/around.rabl @@ -12,7 +12,7 @@ child @stop_areas, root: :features, object_root: false do        name: s.name,        short_name: truncate(s.name, :length => 30) || "",        city_name: s.city_name, -      area_type: s.area_type, +      area_type: Chouette::AreaType.find(s.area_type).label,        registration_number: s.registration_number,        stoparea_id: s.id,        text: "#{s.name}, #{s.zip_code} #{s.city_name}", diff --git a/app/views/autocomplete_stop_areas/index.rabl b/app/views/autocomplete_stop_areas/index.rabl index d20051ad5..c92b708f4 100644 --- a/app/views/autocomplete_stop_areas/index.rabl +++ b/app/views/autocomplete_stop_areas/index.rabl @@ -13,7 +13,7 @@ node do |stop_area|    :user_objectid => stop_area.user_objectid,    :longitude => stop_area.longitude,    :latitude => stop_area.latitude, -  :area_type => stop_area.area_type, +  :area_type => Chouette::AreaType.find(stop_area.area_type).label,    :comment => stop_area.comment,    :text => stop_area.full_name    } diff --git a/app/views/networks/_form.html.slim b/app/views/networks/_form.html.slim index 362584f97..f91a112e8 100644 --- a/app/views/networks/_form.html.slim +++ b/app/views/networks/_form.html.slim @@ -4,11 +4,11 @@        = f.input :name, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@line_referential)}.network.name")}        = f.input :registration_number, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@line_referential)}.network.registration_number")}        = f.input :comment -      = f.input :version_date, :label_html => { :class => 'string optional col-sm-4 col-xs-5 control-label' }, :wrapper => :multi_select_inline -      = f.input :description -      = f.input :source_name -      = f.input :source_type_name, as: :select, :collection => Chouette::Network.source_type_name.options, :include_blank => true -      = f.input :source_identifier +      / = f.input :version_date, :label_html => { :class => 'string optional col-sm-4 col-xs-5 control-label' }, :wrapper => :multi_select_inline +      / = f.input :description +      / = f.input :source_name +      / = f.input :source_type_name, as: :select, :collection => Chouette::Network.source_type_name.options, :include_blank => true +      / = f.input :source_identifier    .separator      = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'network_form' diff --git a/app/views/networks/show.html.slim b/app/views/networks/show.html.slim index f7d40a049..8e40a13b2 100644 --- a/app/views/networks/show.html.slim +++ b/app/views/networks/show.html.slim @@ -14,4 +14,8 @@      .row        .col-lg-6.col-md-6.col-sm-12.col-xs-12          = definition_list t('metadatas'), -          { 'ID Codif' => @network.try(:get_objectid).try(:short_id) } +          { @network.human_attribute_name(:id) => @network.get_objectid.try(:short_id), \ +            @network.human_attribute_name(:name) => @network.name, \ +            @network.human_attribute_name(:registration_number) => @network.registration_number, \ +            @network.human_attribute_name(:comment) => (@network.comment.presence || '-'), \ +           } diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim index 305d04f6b..cbb622c44 100644 --- a/app/views/referentials/show.html.slim +++ b/app/views/referentials/show.html.slim @@ -25,7 +25,7 @@          - attributes[@referential.human_attribute_name(:status)] = @referential.referential_read_only? ? "<div class='td-block'><span class='fa fa-archive'></span><span>#{t('activerecord.attributes.referential.archived_at')}</span></div>".html_safe : "<div class='td-block'><span class='sb sb-lg sb-preparing'></span><span>#{t('activerecord.attributes.referential.archived_at_null')}</span></div>".html_safe unless @referential.in_referential_suite?          - attributes[@referential.human_attribute_name(:validity_period)] = (@referential.validity_period.present? ? t('validity_range', debut: l(@referential.try(:validity_period).try(:begin), format: :short), end: l(@referential.try(:validity_period).try(:end), format: :short)) : '-')          - attributes[@referential.human_attribute_name(:organisation)] = @referential.organisation.name -        - attributes[@referential.human_attribute_name(:published_at)] = '-' unless @referential.in_referential_suite? +        - attributes[@referential.human_attribute_name(:merged_at)] = @referential.merged_at ? l(@referential.merged_at, format: :short) : '-' unless @referential.in_referential_suite?          = definition_list t('metadatas'), attributes      - if params[:q].present? or @reflines.any? diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim index 66e90d839..f7796b188 100644 --- a/app/views/vehicle_journeys/index.html.slim +++ b/app/views/vehicle_journeys/index.html.slim @@ -27,6 +27,7 @@    | window.perms = #{raw @perms};    | window.features = #{raw @features};    | window.all_missions = #{(@all_missions.to_json).html_safe}; +  | window.custom_fields = #{(@custom_fields.to_json).html_safe};    | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};  = javascript_pack_tag 'vehicle_journeys/index.js' diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl index eeed79b34..fc65e6cb6 100644 --- a/app/views/vehicle_journeys/show.rabl +++ b/app/views/vehicle_journeys/show.rabl @@ -1,6 +1,6 @@  object @vehicle_journey -[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum].each do |attr| +[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum, :custom_fields].each do |attr|    attributes attr, :unless => lambda { |m| m.send( attr).nil?}  end @@ -59,11 +59,11 @@ child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops        vehicle_stop.stop_point.stop_area.city_name      end -    [:arrival_time, :departure_time].each do |att| -      node(att) do |vs| +    [:arrival, :departure].each do |att| +      node("#{att}_time") do |vs|          { -          hour: vs.send(att).try(:strftime, '%H'), -          minute: vs.send(att).try(:strftime, '%M') +          hour: vs.send("#{att}_local_time").try(:strftime, '%H'), +          minute: vs.send("#{att}_local_time").try(:strftime, '%M')          }        end      end diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim index 17ad75051..8907f3f08 100644 --- a/app/views/workbenches/show.html.slim +++ b/app/views/workbenches/show.html.slim @@ -54,8 +54,8 @@                    attribute: Proc.new {|w| l(w.updated_at, format: :short)} \                  ), \                  TableBuilderHelper::Column.new( \ -                  key: :published_at, \ -                  attribute: '' \ +                  key: :merged_at, \ +                  attribute: Proc.new {|w| w.merged_at ? l(w.merged_at, format: :short) : '-'} \                  ) \                ],                selectable: ->(ref){ @workbench.referentials.include?(ref) }, diff --git a/config/locales/area_types.en.yml b/config/locales/area_types.en.yml index 9f505c5e6..34ec3243d 100644 --- a/config/locales/area_types.en.yml +++ b/config/locales/area_types.en.yml @@ -6,4 +6,3 @@ en:        zdlp: ZDLp        zdlr: ZDLr        lda: LDA - diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml index f41e35446..eb8eae98d 100644 --- a/config/locales/referentials.en.yml +++ b/config/locales/referentials.en.yml @@ -91,7 +91,7 @@ en:          routing_constraint_zone: Routing constraint zone          validity_period: "Inclusive validity period"          updated_at: "Updated" -        published_at: "Integrated" +        merged_at: "Finalized"          archived_at: "Archived"          archived_at_null: "Unarchived"          created_from: 'Created from' diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml index 0f6e71520..37af8a4eb 100644 --- a/config/locales/referentials.fr.yml +++ b/config/locales/referentials.fr.yml @@ -92,7 +92,7 @@ fr:          validity_period: "Période de validité englobante"          updated_at: "Edité le"          created_at: "Créé le" -        published_at: "Intégré le" +        merged_at: "Finalisé le"          archived_at: "Conservé"          archived_at_null: "En préparation"          created_from: 'Créé à partir de' diff --git a/db/migrate/20180111200406_add_merged_at_to_referentials.rb b/db/migrate/20180111200406_add_merged_at_to_referentials.rb new file mode 100644 index 000000000..27b11fa29 --- /dev/null +++ b/db/migrate/20180111200406_add_merged_at_to_referentials.rb @@ -0,0 +1,5 @@ +class AddMergedAtToReferentials < ActiveRecord::Migration +  def change +    add_column :referentials, :merged_at, :datetime +  end +end diff --git a/db/schema.rb b/db/schema.rb index f55800c8b..f2cf6b4b6 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: 20180109180350) do +ActiveRecord::Schema.define(version: 20180111200406) do    # These are extensions that must be enabled in order to support this database    enable_extension "plpgsql" @@ -676,6 +676,7 @@ ActiveRecord::Schema.define(version: 20180109180350) do      t.boolean  "ready",                              default: false      t.integer  "referential_suite_id",     limit: 8      t.string   "objectid_format" +    t.datetime "merged_at"    end    add_index "referentials", ["created_from_id"], name: "index_referentials_on_created_from_id", using: :btree @@ -955,7 +956,7 @@ ActiveRecord::Schema.define(version: 20180109180350) do      t.integer  "route_id",                        limit: 8      t.integer  "journey_pattern_id",              limit: 8      t.integer  "company_id",                      limit: 8 -    t.string   "objectid",                                               null: false +    t.string   "objectid",                                              null: false      t.integer  "object_version",                  limit: 8      t.string   "comment"      t.string   "status_value" @@ -967,13 +968,13 @@ ActiveRecord::Schema.define(version: 20180109180350) do      t.integer  "number",                          limit: 8      t.boolean  "mobility_restricted_suitability"      t.boolean  "flexible_service" -    t.integer  "journey_category",                          default: 0,  null: false +    t.integer  "journey_category",                          default: 0, null: false      t.datetime "created_at"      t.datetime "updated_at"      t.string   "checksum"      t.text     "checksum_source"      t.string   "data_source_ref" -    t.jsonb    "custom_field_values",                       default: {} +    t.jsonb    "custom_field_values"    end    add_index "vehicle_journeys", ["objectid"], name: "vehicle_journeys_objectid_key", unique: true, using: :btree diff --git a/spec/decorators/referential_decorator_spec.rb b/spec/decorators/referential_decorator_spec.rb index 879ab7d4b..9e34a0109 100644 --- a/spec/decorators/referential_decorator_spec.rb +++ b/spec/decorators/referential_decorator_spec.rb @@ -69,6 +69,7 @@ RSpec.describe ReferentialDecorator, type: [:helper, :decorator] do            expect_action_link_elements.to be_empty            expect_action_link_hrefs.to eq([              referential_time_tables_path(object), +            new_referential_path(from: object)            ])          end        end diff --git a/spec/factories/chouette_vehicle_journey_at_stop.rb b/spec/factories/chouette_vehicle_journey_at_stop.rb index 831e347d4..07a4ec557 100644 --- a/spec/factories/chouette_vehicle_journey_at_stop.rb +++ b/spec/factories/chouette_vehicle_journey_at_stop.rb @@ -1,9 +1,9 @@  FactoryGirl.define do    factory :vehicle_journey_at_stop, :class => Chouette::VehicleJourneyAtStop do      association :vehicle_journey, :factory => :vehicle_journey +    association :stop_point, :factory => :stop_point      departure_day_offset { 0 }      departure_time       { Time.now }      arrival_time         { Time.now - 1.hour }    end  end - diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index e82697b0a..8b383d88d 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -55,7 +55,7 @@ describe TableBuilderHelper, type: :helper do              <th><a href="/workbenches/#{workbench.id}?direction=desc&sort=lines">Lignes<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th>              <th><a href="/workbenches/#{workbench.id}?direction=desc&sort=created_at">Créé le<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th>              <th><a href="/workbenches/#{workbench.id}?direction=desc&sort=updated_at">Edité le<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th> -            <th><a href="/workbenches/#{workbench.id}?direction=desc&sort=published_at">Intégré le<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th> +            <th><a href="/workbenches/#{workbench.id}?direction=desc&sort=merged_at">Finalisé le<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th>              <th></th>          </tr>      </thead> @@ -144,7 +144,7 @@ describe TableBuilderHelper, type: :helper do              attribute: Proc.new {|w| l(w.updated_at, format: :short)}            ),            TableBuilderHelper::Column.new( -            key: :published_at, +            key: :merged_at,              attribute: ''            )          ], diff --git a/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js b/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js new file mode 100644 index 000000000..786b74cc7 --- /dev/null +++ b/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js @@ -0,0 +1,42 @@ +import React, { Component } from 'react' +import CustomFieldsInputs from '../../../../app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs' +import renderer from 'react-test-renderer' +require('select2') +console.log($().jquery) + +describe('CustomFieldsInputs', () => { +  set('values', () => { +    return {} +  }) + +  set('component', () => { +    let inputs = renderer.create( +      <CustomFieldsInputs +        values={values} +        disabled={false} +        onUpdate={()=>{}} +      /> +    ).toJSON() + +    return inputs +  }) + +  it('should match the snapshot', () => { +    expect(component).toMatchSnapshot() +  }) + +  // context('with fields', () => { +  //   set('values', () => { +  //     return { +  //       foo: { +  //         options: { list_values: ["", "1", "2"] }, +  //         field_type: "list", +  //         name: "test" +  //       } +  //     } +  //   }) +  //   it('should match the snapshot', () => { +  //     expect(component).toMatchSnapshot() +  //   }) +  // }) +}) diff --git a/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap b/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap new file mode 100644 index 000000000..c93ec0097 --- /dev/null +++ b/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CustomFieldsInputs should match the snapshot 1`] = `<div />`; diff --git a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js index 44e11aadf..044e95799 100644 --- a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js +++ b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js @@ -89,7 +89,12 @@ describe('vehicleJourneys reducer', () => {      }]      let fakeData = {        published_journey_name: {value: 'test'}, -      published_journey_identifier: {value : ''} +      published_journey_identifier: {value : ''}, +      custom_fields: { +        foo: { +          value: 12 +        } +      }      }      let fakeSelectedJourneyPattern = {id: "1"}      let fakeSelectedCompany = {name: "ALBATRANS"} @@ -115,7 +120,12 @@ describe('vehicleJourneys reducer', () => {        selected: false,        deletable: false,        transport_mode: 'undefined', -      transport_submode: 'undefined' +      transport_submode: 'undefined', +      custom_fields: { +        foo: { +          value: 12 +        } +      }      }, ...state])    }) @@ -345,12 +355,18 @@ describe('vehicleJourneys reducer', () => {    })    it('should handle EDIT_VEHICLEJOURNEY', () => { +    let custom_fields = { +      foo: { +        value: 12 +      } +    }      let fakeData = {        published_journey_name: {value : 'test'}, -      published_journey_identifier: {value: 'test'} +      published_journey_identifier: {value: 'test'}, +      custom_fields: {foo: {value: 12}}      }      let fakeSelectedCompany : {name : 'ALBATRANS'} -    let newVJ = Object.assign({}, state[0], {company: fakeSelectedCompany, published_journey_name: fakeData.published_journey_name.value, published_journey_identifier: fakeData.published_journey_identifier.value}) +    let newVJ = Object.assign({}, state[0], {company: fakeSelectedCompany, published_journey_name: fakeData.published_journey_name.value, published_journey_identifier: fakeData.published_journey_identifier.value, custom_fields})      expect(        vjReducer(state, {          type: 'EDIT_VEHICLEJOURNEY', diff --git a/spec/models/chouette/vehicle_journey_at_stop_spec.rb b/spec/models/chouette/vehicle_journey_at_stop_spec.rb index df8a630fe..4d4a1794e 100644 --- a/spec/models/chouette/vehicle_journey_at_stop_spec.rb +++ b/spec/models/chouette/vehicle_journey_at_stop_spec.rb @@ -40,6 +40,30 @@ RSpec.describe Chouette::VehicleJourneyAtStop, type: :model do      end    end +  context "the different times" do +    let (:at_stop) { build_stubbed(:vehicle_journey_at_stop) } + +    describe "without a TimeZone" do +      it "should not offset times" do +        expect(at_stop.departure).to eq at_stop.departure_local +        expect(at_stop.arrival).to eq at_stop.arrival_local +      end +    end + + +    describe "with a TimeZone" do +      before(:each) do +        stop = at_stop.stop_point.stop_area +        stop.time_zone = "Mexico City" +      end + +      it "should offset times" do +        expect(at_stop.departure_local).to eq at_stop.send(:format_time, at_stop.departure_time - 6.hours) +        expect(at_stop.arrival_local).to eq at_stop.send(:format_time, at_stop.arrival_time - 6.hours) +      end +    end +  end +    describe "#validate" do      it "displays the proper error message when day offset exceeds the max" do        bad_offset = Chouette::VehicleJourneyAtStop::DAY_OFFSET_MAX + 1 diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb index 06cac6bc7..2a88ac3ce 100644 --- a/spec/models/chouette/vehicle_journey_spec.rb +++ b/spec/models/chouette/vehicle_journey_spec.rb @@ -64,10 +64,12 @@ describe Chouette::VehicleJourney, :type => :model do          at_stop[att.to_s] = vjas.send(att) unless vjas.send(att).nil?        end -      [:arrival_time, :departure_time].map do |att| -        at_stop[att.to_s] = { -          'hour'   => vjas.send(att).strftime('%H'), -          'minute' => vjas.send(att).strftime('%M'), +      at_stop["stop_point_objectid"] = vjas&.stop_point&.objectid + +      [:arrival, :departure].map do |att| +        at_stop["#{att}_time"] = { +          'hour'   => vjas.send("#{att}_local_time").strftime('%H'), +          'minute' => vjas.send("#{att}_local_time").strftime('%M'),          }        end        at_stop @@ -80,6 +82,7 @@ describe Chouette::VehicleJourney, :type => :model do          item['purchase_windows']         = []          item['footnotes']                = []          item['purchase_windows']         = [] +        item['custom_fields']            = vj.custom_fields          vj.vehicle_journey_at_stops.each do |vjas|            item['vehicle_journey_at_stops'] << vehicle_journey_at_stop_to_state(vjas) @@ -94,7 +97,8 @@ describe Chouette::VehicleJourney, :type => :model do      let(:collection)      { [state] }      it 'should create new vj from state' do -      new_vj = build(:vehicle_journey, objectid: nil, published_journey_name: 'dummy', route: route, journey_pattern: journey_pattern) +      create(:custom_field, code: :energy) +      new_vj = build(:vehicle_journey, objectid: nil, published_journey_name: 'dummy', route: route, journey_pattern: journey_pattern, custom_field_values: {energy: 99})        collection << vehicle_journey_to_state(new_vj)        expect {          Chouette::VehicleJourney.state_update(route, collection) @@ -110,6 +114,27 @@ describe Chouette::VehicleJourney, :type => :model do        expect(collection.last['objectid']).to eq obj.objectid        expect(obj.published_journey_name).to eq 'dummy' +      expect(obj.custom_fields["energy"]["value"]).to eq 99 +    end + +    it 'should expect local times' do +      new_vj = build(:vehicle_journey, objectid: nil, published_journey_name: 'dummy', route: route, journey_pattern: journey_pattern) +      stop_area = create(:stop_area, time_zone: "Mexico City") +      stop_point = create(:stop_point, stop_area: stop_area) +      new_vj.vehicle_journey_at_stops << build(:vehicle_journey_at_stop, vehicle_journey: vehicle_journey, stop_point: stop_point) +      data = vehicle_journey_to_state(new_vj) +      data['vehicle_journey_at_stops'][0]["departure_time"]["hour"] = "15" +      data['vehicle_journey_at_stops'][0]["arrival_time"]["hour"] = "12" +      collection << data +      expect { +        Chouette::VehicleJourney.state_update(route, collection) +      }.to change {Chouette::VehicleJourney.count}.by(1) +      created = Chouette::VehicleJourney.last.vehicle_journey_at_stops.last +      expect(created.stop_point).to eq stop_point +      expect(created.departure_local_time.hour).to_not eq created.departure_time.hour +      expect(created.arrival_local_time.hour).to_not eq created.arrival_time.hour +      expect(created.departure_local_time.hour).to eq 15 +      expect(created.arrival_local_time.hour).to eq 12      end      it 'should save vehicle_journey_at_stops of newly created vj' do @@ -209,11 +234,13 @@ describe Chouette::VehicleJourney, :type => :model do      it 'should update vj attributes from state' do        state['published_journey_name']       = 'edited_name'        state['published_journey_identifier'] = 'edited_identifier' +      state['custom_fields'] = {energy: {value: 99}}        Chouette::VehicleJourney.state_update(route, collection)        expect(state['errors']).to be_nil        expect(vehicle_journey.reload.published_journey_name).to eq state['published_journey_name']        expect(vehicle_journey.reload.published_journey_identifier).to eq state['published_journey_identifier'] +      expect(vehicle_journey.reload.custom_field_value("energy")).to eq 99      end      it 'should return errors when validation failed' do diff --git a/spec/models/custom_field_spec.rb b/spec/models/custom_field_spec.rb index 80873683c..6ebf994db 100644 --- a/spec/models/custom_field_spec.rb +++ b/spec/models/custom_field_spec.rb @@ -17,8 +17,15 @@ RSpec.describe CustomField, type: :model do    context "custom fields for a resource" do -    let!( :fields ){ (1..2).map{ create :custom_field } } -    it { expect(vj.custom_fields).to eq(fields) } +    let!( :fields ){ [create(:custom_field), create(:custom_field, code: :energy)] } +    let!( :instance_fields ){ +      { +        fields[0].code => fields[0].slice(:code, :name, :field_type, :options).update(value: nil), +        "energy" => fields[1].slice(:code, :name, :field_type, :options).update(value: 99) +      } +    } +    it { expect(Chouette::VehicleJourney.custom_fields).to eq(fields) } +    it { expect(vj.custom_fields).to eq(instance_fields) }    end    context "custom field_values for a resource" do diff --git a/spec/policies/referential_policy_spec.rb b/spec/policies/referential_policy_spec.rb index 8540d3ce9..778e14901 100644 --- a/spec/policies/referential_policy_spec.rb +++ b/spec/policies/referential_policy_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8  RSpec.describe ReferentialPolicy, type: :policy do    let( :record ){ build_stubbed :referential } @@ -45,9 +46,9 @@ RSpec.describe ReferentialPolicy, type: :policy do    # Custom Permissions    # ------------------ -  permissions :clone? do -    it_behaves_like 'permitted policy', 'referentials.create', archived_and_finalised: true -  end +  # permissions :clone? do +  #   it_behaves_like 'permitted policy', 'referentials.create', archived_and_finalised: true +  # end    permissions :archive? do | 
