diff options
Diffstat (limited to 'app')
89 files changed, 1553 insertions, 370 deletions
diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico Binary files differnew file mode 100644 index 000000000..7029bd04e --- /dev/null +++ b/app/assets/images/favicon.ico diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass index 3f8467efe..632ade179 100644 --- a/app/assets/stylesheets/application.sass +++ b/app/assets/stylesheets/application.sass @@ -21,3 +21,6 @@ @import 'modules/import_messages' @import 'flag-icon' + +span.fa + span + margin-left: 0.2em diff --git a/app/assets/stylesheets/base.sass b/app/assets/stylesheets/base.sass index 83d92076c..43831fb6b 100644 --- a/app/assets/stylesheets/base.sass +++ b/app/assets/stylesheets/base.sass @@ -16,3 +16,7 @@ // OL3 @import 'OpenLayers/ol' + +span.sb, span.fa + & + span + margin-left: 0.3em diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass index b13c5fc23..e7aa31fab 100644 --- a/app/assets/stylesheets/components/_forms.sass +++ b/app/assets/stylesheets/components/_forms.sass @@ -507,10 +507,10 @@ table, .table right: 15px top: 50% padding: 0 - margin-top: -13px z-index: 1 + transform: translateY(-50%) - .btn + *:not(.btn-group) > .btn color: $blue font-weight: 700 background-color: transparent @@ -718,6 +718,10 @@ table, .table > .form-group:last-child border-right: none + @for $i from 1 through 99 + &.w#{$i} + display: inline-block + // Form group date .form-group.date .form-inline diff --git a/app/assets/stylesheets/components/_tables.sass b/app/assets/stylesheets/components/_tables.sass index 66ffe9cb1..4952acf92 100644 --- a/app/assets/stylesheets/components/_tables.sass +++ b/app/assets/stylesheets/components/_tables.sass @@ -68,10 +68,10 @@ font-weight: 700 color: inherit - > .fa + > .fa, > .sb &:first-child margin-right: 3px - + > tr:hover cursor: default > td diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass index 3ff0828ea..9bb19f75f 100644 --- a/app/assets/stylesheets/modules/_vj_collection.sass +++ b/app/assets/stylesheets/modules/_vj_collection.sass @@ -2,7 +2,7 @@ // VJ Collection // //-----------------// -#vehicle_journeys_wip +#vehicle_journeys_wip, .consolidated-view .table-2entries .t2e-head > .td @@ -218,3 +218,95 @@ // Reset default behaviour .form-control border-color: #ccc + +.consolidated-view + $highlighted: #d4ba32 + .togglable + &.ready + transition: all 0.5s + &:not(.open) + min-height: 0 !important + padding: 0 !important + margin: 0 !important + border: none + + .line + & > .head + font-size: 2em + text-transform: capitalize + border-top: 3px solid black + border-bottom: 3px solid black + padding-left: 10px + margin-top: 10px + .routes + .route + background: #F9F9F9 + & > .head + &.highlighted + .pull-right, span.fa + color: $highlighted !important + a + padding: 15px + color: black + font-size: 1.2em + text-transform: capitalize + display: block + text-decoration: none + &:hover + background-color: #F0F0F0 + .fa + color: $red + transition: transform 0.1s + &.active .fa + transform: rotate(180deg) + .pull-right + font-size: 0.9em + text-transform: lowercase + .vehicle-journeys + display: block + overflow: hidden + margin-bottom: 0px + & > * + display: inline-block + & > * + overflow: hidden + min-width: 0 + &.open + margin-bottom: 40px + + .highlighted + background-color: lighten($highlighted, 20%) !important + .disabled + color: #bbb + .t2e-item-list .t2e-item + .th + min-width: 100px + max-width: 150px + & > div + text-overflow: ellipsis + overflow: hidden + white-space: nowrap + .td + text-align: center + &:hover:after + position: absolute + height: 100% + bottom: 0 + left: -10000px + right: -10000px + content: "" + background-color: $red + opacity: 0.1 + z-index: 10 + &.headlined:hover:after + height: 50% + + + .table-2entries > .t2e-head > .td > div > span::after + bottom: -6px !important + + .table.table-2entries .t2e-item-list .t2e-item + background-color: #F9F9F9 + + .table.table-2entries .td > div.headlined::before + border-right: none diff --git a/app/controllers/clean_ups_controller.rb b/app/controllers/clean_ups_controller.rb index c25df1a00..350f9ae87 100644 --- a/app/controllers/clean_ups_controller.rb +++ b/app/controllers/clean_ups_controller.rb @@ -3,6 +3,8 @@ class CleanUpsController < ChouetteController respond_to :html, :only => [:create] belongs_to :referential + defaults :resource_class => CleanUp + def create @clean_up = CleanUp.new(clean_up_params) @clean_up.referential = @referential diff --git a/app/controllers/compliance_check_messages_controller.rb b/app/controllers/compliance_check_messages_controller.rb index 36745981e..db551cca5 100644 --- a/app/controllers/compliance_check_messages_controller.rb +++ b/app/controllers/compliance_check_messages_controller.rb @@ -7,7 +7,7 @@ class ComplianceCheckMessagesController < ChouetteController def index index! do |format| format.csv { - send_data ComplianceCheckMessageExport.new(compliance_check_messages: collection).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true, server_url: request.base_url) , :filename => "compliance_check_set_errors_#{line_code}_#{Date.today.to_s}.csv" + send_data ComplianceCheckMessageExport.new(compliance_check_messages: collection).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true, server_url: request.base_url) , :filename => "#{t('compliance_check_messages.compliance_check_set_errors')}_#{line_code}_#{Time.now.strftime('%d-%m-%Y_%H-%M')}.csv" } end end @@ -22,10 +22,10 @@ class ComplianceCheckMessagesController < ChouetteController end def compliance_check_resource - ComplianceCheckResource.find(params[:compliance_check_resource_id]) + ComplianceCheckResource.find(params[:compliance_check_resource_id]) end - private + private def line_code Chouette::Line.find_by_objectid("#{compliance_check_resource.reference}").get_objectid.local_id diff --git a/app/controllers/concerns/referential_support.rb b/app/controllers/concerns/referential_support.rb index fe75e3579..f606e0e63 100644 --- a/app/controllers/concerns/referential_support.rb +++ b/app/controllers/concerns/referential_support.rb @@ -8,6 +8,7 @@ module ReferentialSupport end def switch_referential + authorize referential, :browse? Apartment::Tenant.switch!(referential.slug) end diff --git a/app/controllers/import_messages_controller.rb b/app/controllers/import_messages_controller.rb index e9a071177..9f61940a3 100644 --- a/app/controllers/import_messages_controller.rb +++ b/app/controllers/import_messages_controller.rb @@ -9,7 +9,7 @@ class ImportMessagesController < ChouetteController def index index! do |format| format.csv { - send_data Import::MessageExport.new(:import_messages => @import_messages).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true) , :filename => "import_errors_#{@import_resource.name.gsub('.xml', '')}_#{Date.today.to_s}.csv" + send_data Import::MessageExport.new(:import_messages => @import_messages).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true) , :filename => "#{t('import_messages.import_errors')}_#{@import_resource.name.gsub('.xml', '')}_#{Time.now.strftime("%d-%m-%Y_%H-%M")}.csv" } end end diff --git a/app/controllers/import_resources_controller.rb b/app/controllers/import_resources_controller.rb index 1535fd171..46f8f0337 100644 --- a/app/controllers/import_resources_controller.rb +++ b/app/controllers/import_resources_controller.rb @@ -24,6 +24,15 @@ class ImportResourcesController < ChouetteController @import_resources ||= parent.resources end + def resource + @import ||= Import::Base.find params[:import_id] + @import_resource ||= begin + import_resource = Import::Resource.find params[:id] + raise ActiveRecord::RecordNotFound unless import_resource.import == @import + import_resource + end + end + private def decorate_import_resources(import_resources) diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index 8d7a723a0..b98d7da8d 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -4,6 +4,7 @@ class ImportsController < ChouetteController include IevInterfaces skip_before_action :authenticate_user!, only: [:download] defaults resource_class: Import::Base, collection_name: 'imports', instance_name: 'import' + before_action :notify_parents def download if params[:token] == resource.token_download @@ -18,7 +19,7 @@ class ImportsController < ChouetteController def index_model Import::Workbench end - + def build_resource @import ||= Import::Workbench.new(*resource_params) do |import| import.workbench = parent @@ -43,4 +44,10 @@ class ImportsController < ChouetteController } ) end + + def notify_parents + if Rails.env.development? + ParentNotifier.new(Import::Base).notify_when_finished + end + end end diff --git a/app/controllers/referential_vehicle_journeys_controller.rb b/app/controllers/referential_vehicle_journeys_controller.rb index 14f7909b9..111d39c2b 100644 --- a/app/controllers/referential_vehicle_journeys_controller.rb +++ b/app/controllers/referential_vehicle_journeys_controller.rb @@ -42,9 +42,9 @@ class ReferentialVehicleJourneysController < ChouetteController @q = @q.ransack(params[:q]) @vehicle_journeys ||= @q.result @vehicle_journeys = parse_order @vehicle_journeys - @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10 @all_companies = Chouette::Company.where("id IN (#{@referential.vehicle_journeys.select(:company_id).to_sql})").distinct - + @consolidated = ReferentialConsolidated.new @vehicle_journeys, params + @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10 end def parse_order scope diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index fe661651e..80f954cde 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -31,7 +31,7 @@ class ReferentialsController < ChouetteController end def show - resource.switch + resource.switch if resource.ready? show! do |format| @referential = @referential.decorate() @reflines = lines_collection.paginate(page: params[:page], per_page: 10) @@ -136,7 +136,6 @@ class ReferentialsController < ChouetteController def create_resource(referential) referential.organisation = current_organisation - referential.ready = true super end diff --git a/app/controllers/workbenches_controller.rb b/app/controllers/workbenches_controller.rb index 35438eaaf..d4dfdebe3 100644 --- a/app/controllers/workbenches_controller.rb +++ b/app/controllers/workbenches_controller.rb @@ -5,7 +5,7 @@ class WorkbenchesController < ChouetteController defaults resource_class: Workbench include PolicyChecker - + respond_to :html, except: :destroy def index @@ -42,7 +42,7 @@ class WorkbenchesController < ChouetteController private def workbench_params - params.require(:workbench).permit(:import_compliance_control_set_id, :merge_compliance_control_set_id) + params.require(:workbench).permit(compliance_control_set_ids: @workbench.workgroup.compliance_control_sets_by_workbench.keys) end def resource @@ -50,7 +50,7 @@ class WorkbenchesController < ChouetteController end def sort_result collection - col = (Workbench.find(params[:id]).referentials.column_names + %w{lines validity_period}).include?(params[:sort]) ? params[:sort] : 'name' + col = (Referential.column_names + %w{lines validity_period}).include?(params[:sort]) ? params[:sort] : 'name' dir = %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' if ['lines', 'validity_period'].include?(col) @@ -75,16 +75,41 @@ class WorkbenchesController < ChouetteController # Fake ransack filter def ransack_status scope - archived = !params[:q]['archived_at_not_null'].to_i.zero? - unarchived = !params[:q]['archived_at_null'].to_i.zero? - - # Both status checked, means no filter - return scope unless archived || unarchived - return scope if archived && unarchived + sql = scope.to_sql + filters = [] + (params[:q] && params[:q][:state] || {}).each do |k, v| + if v == "1" + + # We get the specific part of the SQL QUERY + # It looks a bit weird, bu this way we don't have to duplicate the + # logic of the scopes + filter_sql = scope.send(k).to_sql + j = 0 + while filter_sql[j] == sql[j] + j += 1 + end + i = j + while filter_sql[j] != sql[i] + j += 1 + end + + filter_sql = filter_sql[i..j] + filter_sql = filter_sql.strip + filter_sql = filter_sql.gsub /^AND\s*/i, '' + filters << filter_sql + end + end - scope = scope.where(archived_at: nil) if unarchived - scope = scope.where("archived_at is not null") if archived - scope + # archived = !params[:q]['archived_at_not_null'].to_i.zero? + # unarchived = !params[:q]['archived_at_null'].to_i.zero? + # + # # Both status checked, means no filter + # return scope unless archived || unarchived + # return scope if archived && unarchived + # + # scope = scope.where(archived_at: nil) if unarchived + # scope = scope.where("archived_at is not null") if archived + scope.where filters.map{|f| "(#{f})"}.join('OR') end # Ignore archived_at_not_null/archived_at_null managed by ransack_status scope diff --git a/app/controllers/workgroups_controller.rb b/app/controllers/workgroups_controller.rb new file mode 100644 index 000000000..3acea248d --- /dev/null +++ b/app/controllers/workgroups_controller.rb @@ -0,0 +1,13 @@ +class WorkgroupsController < ChouetteController + defaults resource_class: Workgroup + + include PolicyChecker + + def show + redirect_to "/" + end + + def workgroup_params + params[:workgroup].permit(workbenches_attributes: [:id, compliance_control_set_ids: @workgroup.compliance_control_sets_by_workgroup.keys]) + end +end diff --git a/app/decorators/referential_decorator.rb b/app/decorators/referential_decorator.rb index cce14d160..db6261120 100644 --- a/app/decorators/referential_decorator.rb +++ b/app/decorators/referential_decorator.rb @@ -5,17 +5,17 @@ class ReferentialDecorator < AF83::Decorator instance_decorator.show_action_link instance_decorator.edit_action_link - instance_decorator.action_link feature: :referential_vehicle_journeys, secondary: :show, on: :show do |l| + instance_decorator.action_link feature: :referential_vehicle_journeys, secondary: :show, on: :show, policy: :browse do |l| l.content t('referential_vehicle_journeys.index.title') l.href { h.referential_vehicle_journeys_path(object) } end - instance_decorator.action_link feature: :purchase_windows, secondary: :show, on: :show do |l| + instance_decorator.action_link feature: :purchase_windows, secondary: :show, on: :show, policy: :browse do |l| l.content t('purchase_windows.index.title') l.href { h.referential_purchase_windows_path(object) } end - instance_decorator.action_link secondary: :show do |l| + instance_decorator.action_link secondary: :show, policy: :browse do |l| l.content t('time_tables.index.title') l.href { h.referential_time_tables_path(object) } end @@ -36,7 +36,7 @@ class ReferentialDecorator < AF83::Decorator l.method :put end - instance_decorator.action_link policy: :unarchive, secondary: :show, on: :show do |l| + instance_decorator.action_link policy: :unarchive, secondary: :show do |l| l.content t('actions.unarchive') l.href { h.unarchive_referential_path(object.id) } l.method :put diff --git a/app/decorators/stop_point_decorator.rb b/app/decorators/stop_point_decorator.rb index 4ff5bce9c..575938fa2 100644 --- a/app/decorators/stop_point_decorator.rb +++ b/app/decorators/stop_point_decorator.rb @@ -4,8 +4,8 @@ class StopPointDecorator < AF83::Decorator with_instance_decorator do |instance_decorator| instance_decorator.show_action_link do |l| l.href do - h.referential_stop_area_path( - object.referential, + h.stop_area_referential_stop_area_path( + object.stop_area.stop_area_referential, object.stop_area ) end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 702ca0ffc..7a3f7e719 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -36,7 +36,7 @@ module ApplicationHelper display = policy(object).synchronize? if policy(object).respond_to?(:synchronize?) rescue false if display info = t('last_update', time: l(object.updated_at, format: :short)) - if object.has_metadata? + if object.try(:has_metadata?) author = object.metadata.modifier_username || t('default_whodunnit') info = "#{info} <br/> #{t('whodunnit', author: author)}" end diff --git a/app/helpers/exports_helper.rb b/app/helpers/exports_helper.rb index 2e784ad35..f30a80ed9 100644 --- a/app/helpers/exports_helper.rb +++ b/app/helpers/exports_helper.rb @@ -17,7 +17,7 @@ module ExportsHelper message.message_attributes["text"] else t([message.class.name.underscore.gsub('/', '_').pluralize, message.message_key].join('.'), message.message_attributes&.symbolize_keys || {}) - end + end.html_safe end def fields_for_export_task_format(form) diff --git a/app/helpers/imports_helper.rb b/app/helpers/imports_helper.rb index 140660153..f06d77eca 100644 --- a/app/helpers/imports_helper.rb +++ b/app/helpers/imports_helper.rb @@ -2,33 +2,49 @@ module ImportsHelper # Import statuses helper - def import_status(status) - if %w[new running pending].include? status + def import_status(status, verbose: false, default_status: nil) + status ||= default_status + return unless status + status = status.to_s.downcase + out = if %w[new running pending].include? status content_tag :span, '', class: "fa fa-clock-o" else cls ='' cls = 'success' if status == 'successful' + cls = 'success' if status == 'ok' cls = 'warning' if status == 'warning' - cls = 'danger' if %w[failed aborted canceled].include? status + cls = 'danger' if %w[failed aborted canceled error].include? status content_tag :span, '', class: "fa fa-circle text-#{cls}" end + if verbose + out += content_tag :span do + txt = "imports.status.#{status}".t(fallback: "") + end + end + out end # Compliance check set messages def bootstrap_class_for_message_criticity message_criticity - case message_criticity - when "error" + case message_criticity.downcase + when "error", "aborted" "alert alert-danger" when "warning" "alert alert-warning" when "info" "alert alert-info" + when "ok", "success" + "alert alert-success" else message_criticity.to_s end end + def import_message_content message + export_message_content message + end + ############################## # TO CLEAN!!! ############################## diff --git a/app/helpers/referentials_helper.rb b/app/helpers/referentials_helper.rb index 9b5b13ace..1f396d43a 100644 --- a/app/helpers/referentials_helper.rb +++ b/app/helpers/referentials_helper.rb @@ -12,6 +12,24 @@ module ReferentialsHelper end end + def icon_for_referential_state state + case state.to_s + when "pending" + "<span class='fa fa-clock-o'></span>" + when "failed" + "<span class='fa fa-times'></span>" + when "archived" + "<span class='fa fa-archive'></span>" + else + "<span class='sb sb-lg sb-preparing'></span>" + end.html_safe + end + + def referential_state referential, icon: true + state_icon = icon && icon_for_referential_state(@referential.state) + "<div class='td-block'>#{state_icon}<span>#{"referentials.states.#{referential.state}".t}</span></div>".html_safe + end + def referential_overview referential service = ReferentialOverview.new referential, self render partial: "referentials/overview", locals: {referential: referential, overview: service} diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 16081b660..7d4885312 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -15,7 +15,7 @@ module SearchHelper if val.is_a?(Array) active = val.any? &:present? elsif val.is_a?(Hash) - active = val.values.any? {|v| v.present? && v != "false" } + active = val.values.any? {|v| v.present? && v != "false" && v != "0" } else active = true end diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb index e2aa2e9ea..0b24a9c05 100644 --- a/app/helpers/table_builder_helper.rb +++ b/app/helpers/table_builder_helper.rb @@ -153,7 +153,17 @@ module TableBuilderHelper i = columns.index(column) if overhead[i].blank? - if (i > 0) && (overhead[i - 1][:width] > 1) + prev = nil + if i > 0 + (i-1..0).each do |j| + o = overhead[j] + if (j + o[:width].to_i) >= i + prev = o + break + end + end + end + if prev clsArrayH = overhead[i - 1][:cls].split hcont << content_tag(:th, build_column_header( @@ -225,7 +235,7 @@ module TableBuilderHelper if column.linkable? path = column.link_to(item) - link = value.present? && path.present? ? link_to(value, path) : "" + link = value.present? && path.present? ? link_to(value, path) : value if overhead.empty? bcont << content_tag(:td, link, title: 'Voir', class: extra_class) @@ -234,7 +244,17 @@ module TableBuilderHelper i = columns.index(column) if overhead[i].blank? - if (i > 0) && (overhead[i - 1][:width] > 1) + prev = nil + if i > 0 + (i-1..0).each do |j| + o = overhead[j] + if (j + o[:width].to_i) >= i + prev = o + break + end + end + end + if prev clsArrayAlt = overhead[i - 1][:cls].split bcont << content_tag(:td, link, title: 'Voir', class: td_cls(clsArrayAlt, extra_class)) diff --git a/app/helpers/vehicle_journeys_helper.rb b/app/helpers/vehicle_journeys_helper.rb index 1cc865c62..4d7eb7002 100644 --- a/app/helpers/vehicle_journeys_helper.rb +++ b/app/helpers/vehicle_journeys_helper.rb @@ -69,4 +69,16 @@ module VehicleJourneysHelper ) end + def vehicle_journey_stop_headline prev_sp, sp + if has_feature?(:long_distance_routes) + headline = prev_sp && prev_sp.stop_area.country_code + headline = sp.stop_area.country_code != headline + headline && sp.stop_area.country_name + else + headline = prev_sp && prev_sp.stop_area.city_name + headline = sp.stop_area.city_name != headline + headline && sp.stop_area.city_name + end + end + end diff --git a/app/inputs/full_time_zone_input.rb b/app/inputs/full_time_zone_input.rb index f5d8a9ba2..6138d17f5 100644 --- a/app/inputs/full_time_zone_input.rb +++ b/app/inputs/full_time_zone_input.rb @@ -1,7 +1,20 @@ class FullTimeZoneInput < SimpleForm::Inputs::CollectionSelectInput def collection @collection ||= begin - collection = options.delete(:collection) || ActiveSupport::TimeZone::MAPPING + collection = options.delete(:collection) || begin + coll = {} + + TZInfo::Timezone.all_data_zones.map do |tzinfo| + # v = ActiveSupport::TimeZone.zones_map[k] + # coll.sort_by do |v| + # "(#{v.formatted_offset}) #{v.name}" + # end + next if tzinfo.friendly_identifier =~ /^etc/i + tz = ActiveSupport::TimeZone.new tzinfo.name#, nil, tzinfo + coll[[tz.utc_offset, tzinfo.friendly_identifier(true)]] = ["(#{tz.formatted_offset}) #{tzinfo.friendly_identifier(true)}", tz.name] + end + coll.sort.map(&:last) + end collection.respond_to?(:call) ? collection.call : collection.to_a end end @@ -9,12 +22,8 @@ class FullTimeZoneInput < SimpleForm::Inputs::CollectionSelectInput def detect_collection_methods label, value = options.delete(:label_method), options.delete(:value_method) - label ||= ->(tz) do - tz = ActiveSupport::TimeZone[tz.last] - "(#{tz.formatted_offset}) #{tz.name}" - end + label ||= :first value ||= :last - [label, value] end diff --git a/app/javascript/helpers/CustomFieldsInputs.js b/app/javascript/helpers/CustomFieldsInputs.js index 0a57e7566..93611538e 100644 --- a/app/javascript/helpers/CustomFieldsInputs.js +++ b/app/javascript/helpers/CustomFieldsInputs.js @@ -43,7 +43,7 @@ export default class CustomFieldsInputs extends Component { ref={'custom_fields.' + cf.code} className='form-control' disabled={this.props.disabled} - value={cf.value || this.options(cf).default} + value={cf.value || this.options(cf).default || ""} onChange={(e) => {this.props.onUpdate(cf.code, e.target.value); this.forceUpdate()} } /> ) @@ -56,7 +56,7 @@ export default class CustomFieldsInputs extends Component { ref={'custom_fields.' + cf.code} className='form-control' disabled={this.props.disabled} - value={cf.value || this.options(cf).default} + value={cf.value || this.options(cf).default || ""} onChange={(e) => {this.props.onUpdate(cf.code, e.target.value); this.forceUpdate()} } /> ) diff --git a/app/javascript/journey_patterns/reducers/journeyPatterns.js b/app/javascript/journey_patterns/reducers/journeyPatterns.js index 1a6a27da6..9dcd82082 100644 --- a/app/javascript/journey_patterns/reducers/journeyPatterns.js +++ b/app/javascript/journey_patterns/reducers/journeyPatterns.js @@ -18,6 +18,7 @@ const journeyPattern = (state = {}, action) =>{ registration_number: action.data.registration_number.value, stop_points: stopPoints, costs: {}, + custom_fields: action.data.custom_fields, deletable: false } case 'UPDATE_CHECKBOX_VALUE': diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index 60496e0ff..98594083d 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -489,23 +489,28 @@ const actions = { } return 0 }, - getDelta: (vjas) => { + getDelta: (vjas, allowNegative=false) => { let delta = 0 if (vjas.departure_time.hour != '' && vjas.departure_time.minute != '' && vjas.arrival_time.hour != '' && vjas.departure_time.minute != ''){ delta = (parseInt(vjas.departure_time.hour) - parseInt(vjas.arrival_time.hour)) * 60 + (parseInt(vjas.departure_time.minute) - parseInt(vjas.arrival_time.minute)) } + if(!true && delta < 0){ + delta += 24*60 + } vjas.delta = delta return vjas }, adjustSchedule: (action, schedule, enforceConsistency=false) => { // we enforce that the departure time remains after the arrival time - actions.getDelta(schedule) + actions.getDelta(schedule, true) if(enforceConsistency && schedule.delta < 0){ - if(action.isDeparture){ - schedule.arrival_time = schedule.departure_time - } - else{ - schedule.departure_time = schedule.arrival_time + if(schedule.arrival_time.hour < 23 || schedule.departure_time.hour > 0){ + if(action.isDeparture){ + schedule.arrival_time = schedule.departure_time + } + else{ + schedule.departure_time = schedule.arrival_time + } } actions.getDelta(schedule) } diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index f7ae9341f..46d300e6e 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -192,20 +192,16 @@ export default class VehicleJourney extends Component { <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' - min='00' - max='23' className='form-control' disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false} readOnly={!this.props.editMode && !vj.dummy} onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}} - onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false, true)}} + onBlur={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false, true)}} value={vj.arrival_time['hour']} /> <span>:</span> <input type='number' - min='00' - max='59' className='form-control' disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false} readOnly={!this.props.editMode && !vj.dummy} @@ -225,8 +221,6 @@ export default class VehicleJourney extends Component { <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false) ? 'disabled ' : '') + 'input-group time'}> <input type='number' - min='00' - max='23' className='form-control' disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false} readOnly={!this.props.editMode && !vj.dummy} @@ -237,8 +231,6 @@ export default class VehicleJourney extends Component { <span>:</span> <input type='number' - min='00' - max='59' className='form-control' disabled={!this.props.editMode || this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.update'] == false} readOnly={!this.props.editMode && !vj.dummy} diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js index 121be6a00..4931ab46e 100644 --- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js @@ -66,10 +66,6 @@ const vehicleJourney= (state = {}, action, keep) => { newVjas.departure_day_offset = 1 newVjas.arrival_day_offset = 1 } - if(current_time.hour + offsetHours < 0){ - newVjas.departure_day_offset = -1 - newVjas.arrival_day_offset = -1 - } } else{ newVjas = { @@ -150,6 +146,16 @@ const vehicleJourney= (state = {}, action, keep) => { return _.assign({}, state, {vehicle_journey_at_stops: shiftedArray}) case 'UPDATE_TIME': let vj, vjas, vjasArray, newSchedule + let val = action.val + if(val != ''){ + val = parseInt(val) + if(action.timeUnit == "minute"){ + val = (val + 60) % 60 + } + else{ + val = (val + 24) % 24 + } + } vjasArray = state.vehicle_journey_at_stops.map((vjas, i) =>{ if(i == action.subIndex){ newSchedule = { @@ -157,13 +163,13 @@ const vehicleJourney= (state = {}, action, keep) => { arrival_time: _.assign({}, vjas.arrival_time) } if (action.isDeparture){ - newSchedule.departure_time[action.timeUnit] = actions.pad(action.val, action.timeUnit) + newSchedule.departure_time[action.timeUnit] = actions.pad(val, action.timeUnit) if(!action.isArrivalsToggled) newSchedule.arrival_time[action.timeUnit] = newSchedule.departure_time[action.timeUnit] newSchedule = actions.adjustSchedule(action, newSchedule, action.enforceConsistency) return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta}) }else{ - newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit) + newSchedule.arrival_time[action.timeUnit] = actions.pad(val, action.timeUnit) newSchedule = actions.adjustSchedule(action, newSchedule, action.enforceConsistency) return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta}) } diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb index 7a8d043e0..949b18d6f 100644 --- a/app/models/chouette/route.rb +++ b/app/models/chouette/route.rb @@ -72,6 +72,9 @@ module Chouette end end + has_many :time_tables, :through => :vehicle_journeys + has_many :purchase_windows, :through => :vehicle_journeys + accepts_nested_attributes_for :stop_points, :allow_destroy => :true validates_presence_of :name diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 8b5354863..818287b04 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -355,32 +355,48 @@ module Chouette end end - def fill_passing_time_at_borders - encountered_borders = [] + def fill_passing_times! + encountered_empty_vjas = [] previous_stop = nil vehicle_journey_at_stops.each do |vjas| sp = vjas.stop_point - if sp.stop_area.area_type == "border" - encountered_borders << vjas + if vjas.arrival_time.nil? && vjas.departure_time.nil? + encountered_empty_vjas << vjas else - if encountered_borders.any? - before_cost = journey_pattern.costs_between previous_stop.stop_point, encountered_borders.first.stop_point - after_cost = journey_pattern.costs_between encountered_borders.last.stop_point, sp - if before_cost && before_cost[:distance] && after_cost && after_cost[:distance] - before_distance = before_cost[:distance].to_f - after_distance = after_cost[:distance].to_f + if encountered_empty_vjas.any? + raise "Cannot extrapolate passing times without an initial time" if previous_stop.nil? + distance_between_known = 0 + distance_from_last_known = 0 + cost = journey_pattern.costs_between previous_stop.stop_point, encountered_empty_vjas.first.stop_point + raise "MISSING cost between #{previous_stop.stop_point.stop_area.registration_number} AND #{encountered_empty_vjas.first.stop_point.stop_area.registration_number}" unless cost.present? + distance_between_known += cost[:distance].to_f + cost = journey_pattern.costs_between encountered_empty_vjas.last.stop_point, sp + raise "MISSING cost between #{encountered_empty_vjas.last.stop_point.stop_area.registration_number} AND #{sp.stop_area.registration_number}" unless cost.present? + distance_between_known += cost[:distance].to_f + distance_between_known += encountered_empty_vjas.each_slice(2).inject(0) do |sum, slice| + cost = journey_pattern.costs_between slice.first.stop_point, slice.last.stop_point + raise "MISSING cost between #{slice.first.stop_point.stop_area.registration_number} AND #{slice.last.stop_point.stop_area.registration_number}" unless cost.present? + sum + cost[:distance].to_f + end + + previous = previous_stop + encountered_empty_vjas.each do |empty_vjas| + cost = journey_pattern.costs_between previous.stop_point, empty_vjas.stop_point + raise "MISSING cost between #{previous.stop_point.stop_area.registration_number} AND #{empty_vjas.stop_point.stop_area.registration_number}" unless cost.present? + distance_from_last_known += cost[:distance] + arrival_time = vjas.arrival_time + (vjas.arrival_day_offset - previous_stop.departure_day_offset)*24.hours - time = previous_stop.departure_time + before_distance / (before_distance+after_distance) * (arrival_time - previous_stop.departure_time) + time = previous_stop.departure_time + distance_from_last_known.to_f / distance_between_known.to_f * (arrival_time - previous_stop.departure_time) day_offset = time.day - 1 time -= day_offset*24.hours - encountered_borders.each do |b| - b.update_attribute :arrival_time, time - b.update_attribute :arrival_day_offset, previous_stop.arrival_day_offset + day_offset - b.update_attribute :departure_time, time - b.update_attribute :departure_day_offset, previous_stop.departure_day_offset + day_offset - end + + empty_vjas.update_attribute :arrival_time, time + empty_vjas.update_attribute :arrival_day_offset, previous_stop.arrival_day_offset + day_offset + empty_vjas.update_attribute :departure_time, time + empty_vjas.update_attribute :departure_day_offset, previous_stop.departure_day_offset + day_offset + previous = empty_vjas end - encountered_borders = [] + encountered_empty_vjas = [] end previous_stop = vjas end diff --git a/app/models/clean_up.rb b/app/models/clean_up.rb index 761fc47be..9cf2389c9 100644 --- a/app/models/clean_up.rb +++ b/app/models/clean_up.rb @@ -12,6 +12,12 @@ class CleanUp < ApplicationModel validate :end_date_must_be_greater_that_begin_date after_commit :perform_cleanup, :on => :create + scope :for_referential, ->(referential) do + where(referential_id: referential.id) + end + + attr_accessor :methods + def end_date_must_be_greater_that_begin_date if self.end_date && self.date_type == 'between' && self.begin_date >= self.end_date errors.add(:base, I18n.t('activerecord.errors.models.clean_up.invalid_period')) @@ -24,31 +30,37 @@ class CleanUp < ApplicationModel def clean referential.switch - - {}.tap do |result| - if date_type - processed = send("destroy_time_tables_#{self.date_type}") - if processed - result['time_table'] = processed[:time_tables].try(:count) - result['vehicle_journey'] = processed[:vehicle_journeys].try(:count) - end - result['time_table_date'] = send("destroy_time_tables_dates_#{self.date_type}").try(:count) - result['time_table_period'] = send("destroy_time_tables_periods_#{self.date_type}").try(:count) - self.overlapping_periods.each do |period| - exclude_dates_in_overlapping_period(period) + referential.pending_while do + {}.tap do |result| + if date_type + processed = send("destroy_time_tables_#{self.date_type}") + if processed + result['time_table'] = processed[:time_tables].try(:count) + result['vehicle_journey'] = processed[:vehicle_journeys].try(:count) + end + result['time_table_date'] = send("destroy_time_tables_dates_#{self.date_type}").try(:count) + result['time_table_period'] = send("destroy_time_tables_periods_#{self.date_type}").try(:count) + self.overlapping_periods.each do |period| + exclude_dates_in_overlapping_period(period) + end end - end - destroy_vehicle_journeys_outside_referential - # Disabled for the moment. See #5372 - # destroy_time_tables_outside_referential + destroy_routes_outside_referential + # Disabled for the moment. See #5372 + # destroy_time_tables_outside_referential - destroy_vehicle_journeys - destroy_journey_patterns - destroy_routes + # Run caller-specified cleanup methods + run_methods + end end end + def run_methods + return if methods.nil? + + methods.each { |method| send(method) } + end + def destroy_time_tables_between time_tables = Chouette::TimeTable.where('end_date < ? AND start_date > ?', self.end_date, self.begin_date) self.destroy_time_tables(time_tables) @@ -95,9 +107,9 @@ class CleanUp < ApplicationModel destroy_time_tables(time_tables) end - def destroy_vehicle_journeys_outside_referential + def destroy_routes_outside_referential line_ids = referential.metadatas.pluck(:line_ids).flatten.uniq - Chouette::VehicleJourney.joins(:route).where(["routes.line_id not in (?)", line_ids]).destroy_all + Chouette::Route.where(['line_id not in (?)', line_ids]).destroy_all end def destroy_vehicle_journeys @@ -112,6 +124,12 @@ class CleanUp < ApplicationModel Chouette::Route.where("id not in (select distinct route_id from journey_patterns)").destroy_all end + def destroy_empty + destroy_vehicle_journeys + destroy_journey_patterns + destroy_routes + end + def overlapping_periods self.end_date = self.begin_date if self.date_type != 'between' Chouette::TimeTablePeriod.where('(period_start, period_end) OVERLAPS (?, ?)', self.begin_date, self.end_date) diff --git a/app/models/compliance_check_set.rb b/app/models/compliance_check_set.rb index 8b1dbdd68..f29ff4de5 100644 --- a/app/models/compliance_check_set.rb +++ b/app/models/compliance_check_set.rb @@ -26,6 +26,10 @@ class ComplianceCheckSet < ApplicationModel %w(successful failed warning aborted canceled) end + def successful? + status.to_s == "successful" + end + def self.abort_old where( 'created_at < ? AND status NOT IN (?)', @@ -68,6 +72,11 @@ class ComplianceCheckSet < ApplicationModel end update attributes + import_resource&.next_step + end + + def import_resource + referential&.import_resources.main_resources.last end diff --git a/app/models/concerns/checksum_support.rb b/app/models/concerns/checksum_support.rb index fe52604bb..86bbd1d00 100644 --- a/app/models/concerns/checksum_support.rb +++ b/app/models/concerns/checksum_support.rb @@ -10,19 +10,24 @@ module ChecksumSupport end module ClassMethods + def has_checksum_children klass, opts={} parent_class = self belongs_to = opts[:relation] || self.model_name.singular has_many = opts[:relation] || self.model_name.plural Rails.logger.debug "Define callback in #{klass} to update checksums #{self.model_name} (via #{has_many}/#{belongs_to})" - klass.after_save do + + child_update_parent = Proc.new do parents = [] parents << self.send(belongs_to) if klass.reflections[belongs_to].present? parents += self.send(has_many) if klass.reflections[has_many].present? Rails.logger.debug "Request from #{klass.name} checksum updates for #{parents.count} #{parent_class} parent(s)" parents.compact.each &:update_checksum_without_callbacks! end + + klass.after_save &child_update_parent + klass.after_destroy &child_update_parent end end diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb index 6b6621d0c..f5a76f324 100644 --- a/app/models/concerns/custom_fields_support.rb +++ b/app/models/concerns/custom_fields_support.rb @@ -6,7 +6,7 @@ module CustomFieldsSupport after_initialize :initialize_custom_fields def self.custom_fields workgroup - return [] unless workgroup + return CustomField.none unless workgroup fields = CustomField.where(resource_type: self.name.split("::").last) fields = fields.where(workgroup_id: workgroup.id) fields diff --git a/app/models/concerns/iev_interfaces/resource.rb b/app/models/concerns/iev_interfaces/resource.rb index 7f8c3eefd..254f88a33 100644 --- a/app/models/concerns/iev_interfaces/resource.rb +++ b/app/models/concerns/iev_interfaces/resource.rb @@ -4,6 +4,24 @@ module IevInterfaces::Resource included do extend Enumerize enumerize :status, in: %i(OK ERROR WARNING IGNORED), scope: true - validates_presence_of :name, :resource_type, :reference + validates_presence_of :name, :resource_type + end + + def update_status_from_importer importer_status + self.update status: status_from_importer(importer_status) + end + + def status_from_importer importer_status + return nil unless importer_status.present? + { + new: nil, + pending: nil, + successful: :OK, + warning: :WARNING, + failed: :ERROR, + running: nil, + aborted: :ERROR, + canceled: :ERROR + }[importer_status.to_sym] end end diff --git a/app/models/concerns/iev_interfaces/task.rb b/app/models/concerns/iev_interfaces/task.rb index f052b3a8f..e40808009 100644 --- a/app/models/concerns/iev_interfaces/task.rb +++ b/app/models/concerns/iev_interfaces/task.rb @@ -23,10 +23,24 @@ module IevInterfaces::Task where('started_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end) end + scope :for_referential, ->(referential) do + where(referential_id: referential.id) + end + scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') } before_save :initialize_fields, on: :create after_save :notify_parent + + status.values.each do |s| + define_method "#{s}!" do + update status: s + end + + define_method "#{s}?" do + status&.to_s == s + end + end end module ClassMethods @@ -52,13 +66,14 @@ module IevInterfaces::Task end def notify_parent - return unless self.class.finished_statuses.include?(status) + return false unless self.class.finished_statuses.include?(status) - return unless parent.present? - return if notified_parent_at + return false unless parent.present? + return false if notified_parent_at parent.child_change update_column :notified_parent_at, Time.now + true end def children_succeedeed @@ -90,6 +105,10 @@ module IevInterfaces::Task update attributes end + def successful? + status.to_s == "successful" + end + def child_change return if self.class.finished_statuses.include?(status) update_status @@ -108,9 +127,14 @@ module IevInterfaces::Task def call_boiv_iev Rails.logger.error("Begin IEV call for import") + + # Java code expects tasks in NEW status + # Don't change status before calling iev + Net::HTTP.get iev_callback_url Rails.logger.error("End IEV call for import") rescue Exception => e + aborted! logger.error "IEV server error : #{e.message}" logger.error e.backtrace.inspect end diff --git a/app/models/import/base.rb b/app/models/import/base.rb index f98e359d4..dcd710e58 100644 --- a/app/models/import/base.rb +++ b/app/models/import/base.rb @@ -32,8 +32,13 @@ class Import::Base < ApplicationModel Rails.logger.info "update_referentials for #{inspect}" return unless self.class.finished_statuses.include?(status) - children.each do |import| - import.referential.update(ready: true) if import.referential + # We treat all created referentials in a batch + # If a single fails, we consider they all failed + # Ohana means family ! + if self.successful? + children.map(&:referential).compact.each &:active! + else + children.map(&:referential).compact.each &:failed! end end diff --git a/app/models/import/gtfs.rb b/app/models/import/gtfs.rb index a20c468c1..9dab11f0e 100644 --- a/app/models/import/gtfs.rb +++ b/app/models/import/gtfs.rb @@ -1,21 +1,40 @@ class Import::Gtfs < Import::Base after_commit :launch_worker, :on => :create + after_commit do + main_resource.update_status_from_importer self.status + true + end + def launch_worker GtfsImportWorker.perform_async id end + def main_resource + @resource ||= parent.resources.find_or_create_by(name: self.name, resource_type: "referential", reference: self.name) if parent + end + + def next_step + main_resource&.next_step + end + + def create_message args + (main_resource || self).messages.build args + end + def import update status: 'running', started_at: Time.now import_without_status update status: 'successful', ended_at: Time.now + referential&.active! rescue Exception => e update status: 'failed', ended_at: Time.now Rails.logger.error "Error in GTFS import: #{e} #{e.backtrace.join('\n')}" + create_message criticity: :error, message_key: :full_text, message_attributes: {text: e.message} + referential&.failed! ensure notify_parent - referential&.update ready: true end def self.accept_file?(file) @@ -34,6 +53,7 @@ class Import::Gtfs < Import::Base workbench_id: workbench.id, metadatas: [referential_metadata] ) + main_resource.update referential: referential if main_resource end def referential_metadata @@ -130,17 +150,21 @@ class Import::Gtfs < Import::Base end def import_agencies + count = 0 Chouette::Company.transaction do source.agencies.each do |agency| company = line_referential.companies.find_or_initialize_by(registration_number: agency.id) company.attributes = { name: agency.name } save_model company + count += 1 end end + create_message criticity: "info", message_key: "gtfs.agencies.imported", message_attributes: {count: count} end def import_stops + count = 0 Chouette::StopArea.transaction do source.stops.each do |stop| stop_area = stop_area_referential.stop_areas.find_or_initialize_by(registration_number: stop.id) @@ -154,11 +178,14 @@ class Import::Gtfs < Import::Base # TODO correct default timezone save_model stop_area + count += 1 end + create_message criticity: "info", message_key: "gtfs.stops.imported", message_attributes: {count: count} end end def import_routes + count = 0 Chouette::Line.transaction do source.routes.each do |route| line = line_referential.lines.find_or_initialize_by(registration_number: route.id) @@ -177,7 +204,9 @@ class Import::Gtfs < Import::Base line.url = route.url save_model line + count += 1 end + create_message criticity: "info", message_key: "gtfs.routes.imported", message_attributes: {count: count} end end @@ -186,6 +215,7 @@ class Import::Gtfs < Import::Base end def import_trips + count = 0 source.trips.each_slice(100) do |slice| slice.each do |trip| Chouette::Route.transaction do @@ -204,18 +234,20 @@ class Import::Gtfs < Import::Base vehicle_journey = journey_pattern.vehicle_journeys.build route: route vehicle_journey.published_journey_name = trip.headsign.presence || trip.id save_model vehicle_journey + count += 1 time_table = referential.time_tables.find_by(id: time_tables_by_service_id[trip.service_id]) if time_tables_by_service_id[trip.service_id] if time_table vehicle_journey.time_tables << time_table else - messages.create! criticity: "warning", message_key: "gtfs.trips.unkown_service_id", message_attributes: {service_id: trip.service_id} + create_message criticity: "warning", message_key: "gtfs.trips.unkown_service_id", message_attributes: {service_id: trip.service_id} end vehicle_journey_by_trip_id[trip.id] = vehicle_journey.id end end end + create_message criticity: "info", message_key: "gtfs.trips.imported", message_attributes: {count: count} end def import_stop_times @@ -261,6 +293,7 @@ class Import::Gtfs < Import::Base end def import_calendars + count = 0 source.calendars.each_slice(500) do |slice| Chouette::TimeTable.transaction do slice.each do |calendar| @@ -271,11 +304,13 @@ class Import::Gtfs < Import::Base time_table.periods.build period_start: calendar.start_date, period_end: calendar.end_date save_model time_table + count += 1 time_tables_by_service_id[calendar.service_id] = time_table.id end end end + create_message criticity: "info", message_key: "gtfs.calendars.imported", message_attributes: {count: count} end def import_calendar_dates @@ -300,10 +335,10 @@ class Import::Gtfs < Import::Base end def notify_parent - return unless parent.present? - return if notified_parent_at - parent.child_change - update_column :notified_parent_at, Time.now + if super + main_resource.update_status_from_importer self.status + next_step + end end end diff --git a/app/models/import/netex.rb b/app/models/import/netex.rb index f19fde435..753f9128d 100644 --- a/app/models/import/netex.rb +++ b/app/models/import/netex.rb @@ -2,15 +2,39 @@ require 'net/http' class Import::Netex < Import::Base before_destroy :destroy_non_ready_referential - after_commit :call_iev_callback, on: :create + after_commit do + main_resource.update_status_from_importer self.status + true + end - before_save def abort_unless_referential - self.status = 'aborted' unless referential + before_save do + self.referential&.failed! if self.status == 'aborted' || self.status == 'failed' end validates_presence_of :parent + def main_resource + @resource ||= parent.resources.find_or_create_by(name: self.name, resource_type: "referential", reference: self.name) + end + + def notify_parent + if super + main_resource.update_status_from_importer self.status + next_step + end + end + + def next_step + main_resource.next_step + end + + def create_message args + main_resource.messages.create args + end + def create_with_referential! + save unless persisted? + self.referential = Referential.new( name: self.name, @@ -19,15 +43,37 @@ class Import::Netex < Import::Base metadatas: [referential_metadata] ) self.referential.save - if self.referential.invalid? + + if self.referential.valid? + main_resource.update referential: referential + call_iev_callback + save! + else Rails.logger.info "Can't create referential for import #{self.id}: #{referential.inspect} #{referential.metadatas.inspect} #{referential.errors.messages}" - if referential.metadatas.all?{|m| m.line_ids.present? && m.line_ids.empty?} - parent.messages.create criticity: :error, message_key: "referential_creation_missing_lines", message_attributes: {referential_name: referential.name} + + if referential.metadatas.all?{|m| m.line_ids.empty? && m.line_ids.empty?} + create_message criticity: :error, message_key: "referential_creation_missing_lines", message_attributes: {referential_name: referential.name} + elsif (overlapped_referential_ids = referential.overlapped_referential_ids).any? + overlapped = Referential.find overlapped_referential_ids.last + create_message( + criticity: :error, + message_key: "referential_creation_overlapping_existing_referential", + message_attributes: { + referential_name: referential.name, + overlapped_name: overlapped.name, + overlapped_url: Rails.application.routes.url_helpers.referential_path(overlapped) + } + ) else - parent.messages.create criticity: :error, message_key: "referential_creation", message_attributes: {referential_name: referential.name} + create_message( + criticity: :error, + message_key: "referential_creation", + message_attributes: {referential_name: referential.name}, + resource_attributes: referential.errors.messages + ) end - else - save! + self.referential = nil + aborted! end end diff --git a/app/models/import/resource.rb b/app/models/import/resource.rb index 1951daacd..43690755d 100644 --- a/app/models/import/resource.rb +++ b/app/models/import/resource.rb @@ -4,5 +4,49 @@ class Import::Resource < ApplicationModel include IevInterfaces::Resource belongs_to :import, class_name: Import::Base + belongs_to :referential has_many :messages, class_name: "Import::Message", foreign_key: :resource_id + + scope :main_resources, ->{ where(resource_type: "referential") } + + def root_import + import = self.import + import = import.parent while import.parent + import + end + + def next_step + if root_import.class == Import::Workbench + + return unless netex_import&.successful? + + workbench.workgroup.import_compliance_control_sets.map do |key, label| + next unless (control_set = workbench.compliance_control_set(key)).present? + compliance_check_set = workbench_import_check_set key + if compliance_check_set.nil? + ComplianceControlSetCopyWorker.perform_async control_set.id, referential_id, root_import.class.name, root_import.id + end + end + end + end + + def workbench + import.workbench + end + + def workgroup + workbench.workgroup + end + + def netex_import + return unless self.resource_type == "referential" + import.children.where(name: self.reference).last + end + + def workbench_import_check_set key + return unless referential.present? + control_set = referential.workbench.compliance_control_set(key) + return unless control_set.present? + referential.compliance_check_sets.where(compliance_control_set_id: control_set.id, referential_id: referential_id).last + end end diff --git a/app/models/import/workbench.rb b/app/models/import/workbench.rb index 124b9b0d8..95d23fe5b 100644 --- a/app/models/import/workbench.rb +++ b/app/models/import/workbench.rb @@ -9,14 +9,18 @@ class Import::Workbench < Import::Base end end + # def main_resource + # @resource ||= resources.find_or_create_by(name: self.name, resource_type: "workbench_import") + # end + def import_gtfs update_column :status, 'running' update_column :started_at, Time.now - Import::Gtfs.create! parent_id: self.id, workbench: workbench, file: File.new(file.path), name: "Import GTFS", creator: "Web service" + Import::Gtfs.create! parent_type: self.class.name, parent_id: self.id, workbench: workbench, file: File.new(file.path), name: "Import GTFS", creator: "Web service" - update_column :status, 'successful' - update_column :ended_at, Time.now + # update_column :status, 'successful' + # update_column :ended_at, Time.now rescue Exception => e Rails.logger.error "Error while processing GTFS file: #{e}" diff --git a/app/models/merge.rb b/app/models/merge.rb index be1bbedcb..aca2f4d4d 100644 --- a/app/models/merge.rb +++ b/app/models/merge.rb @@ -39,10 +39,14 @@ class Merge < ApplicationModel rescue => e Rails.logger.error "Merge failed: #{e} #{e.backtrace.join("\n")}" update status: :failed + new&.failed! raise e if Rails.env.test? ensure attributes = { ended_at: Time.now } - attributes[:status] = :successful if status == :running + if status == :running + attributes[:status] = :successful + referentials.each &:archived! + end update attributes end @@ -141,12 +145,19 @@ class Merge < ApplicationModel end end + referential_route_opposite_route_ids = referential.switch do + Hash[referential.routes.where('opposite_route_id is not null').pluck(:id, :opposite_route_id)] + end + referential_routing_constraint_zones_new_ids = {} new.switch do + route_ids_mapping = {} + referential_routes.each do |route| existing_route = new.routes.find_by line_id: route.line_id, checksum: route.checksum if existing_route + route_ids_mapping[route.id] = existing_route.id existing_route.merge_metadata_from route else objectid = Chouette::Route.where(objectid: route.objectid).exists? ? nil : route.objectid @@ -155,7 +166,7 @@ class Merge < ApplicationModel objectid: objectid, # line_id is the same # all other primary must be changed - opposite_route_id: nil #FIXME + opposite_route_id: nil # merged after ) new_route = new.routes.build attributes @@ -175,6 +186,8 @@ class Merge < ApplicationModel # We need to create StopPoints to known new primary keys new_route.save! + route_ids_mapping[route.id] = new_route.id + old_stop_point_ids = route_stop_points.sort_by(&:position).map(&:id) new_stop_point_ids = new_route.stop_points.sort_by(&:position).map(&:id) @@ -221,6 +234,20 @@ class Merge < ApplicationModel end end end + + referential_route_opposite_route_ids.each do |route_id, opposite_route_id| + new_route_id = route_ids_mapping[route_id] + new_opposite_route_id = route_ids_mapping[opposite_route_id] + + new_route = nil + if new_route_id && new_opposite_route_id + if new_route = new.routes.find_by(id: new_route_id) + new_route.update_column :opposite_route_id, new_opposite_route_id + end + end + + Rails.logger.warn "Can't merge opposite route for Route #{route_id}" unless new_route + end end # JourneyPatterns diff --git a/app/models/referential.rb b/app/models/referential.rb index 0522d72c0..0c6e71d47 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -3,6 +3,8 @@ class Referential < ApplicationModel include DataFormatEnumerations include ObjectidFormatterSupport + STATES = %i(pending active failed archived) + validates_presence_of :name validates_presence_of :slug validates_presence_of :prefix @@ -24,6 +26,7 @@ class Referential < ApplicationModel has_one :user has_many :api_keys, class_name: 'Api::V1::ApiKey', dependent: :destroy + has_many :import_resources, class_name: 'Import::Resource', dependent: :destroy belongs_to :organisation validates_presence_of :organisation @@ -57,8 +60,13 @@ class Referential < ApplicationModel belongs_to :referential_suite + scope :pending, -> { where(ready: false, failed_at: nil, archived_at: nil) } + scope :active, -> { where(ready: true, failed_at: nil, archived_at: nil) } + scope :failed, -> { where.not(failed_at: nil) } + scope :archived, -> { where.not(archived_at: nil) } scope :ready, -> { where(ready: true) } + scope :in_periode, ->(periode) { where(id: referential_ids_in_periode(periode)) } scope :include_metadatas_lines, ->(line_ids) { where('referential_metadata.line_ids && ARRAY[?]::bigint[]', line_ids) } scope :order_by_validity_period, ->(dir) { joins(:metadatas).order("unnest(periodes) #{dir}") } @@ -116,6 +124,20 @@ class Referential < ApplicationModel @_models_with_checksum || [] end + OPERATIONS = [Import::Netex, Import::Gtfs] + + def last_operation + operations = [] + Referential::OPERATIONS.each do |klass| + operations << klass.for_referential(self).limit(1).select("'#{klass.name}' as kind, id, created_at").order('created_at DESC').to_sql + end + sql = "SELECT * FROM ((#{operations.join(') UNION (')})) AS subquery ORDER BY subquery.created_at DESC" + res = ActiveRecord::Base.connection.execute(sql).first + if res + res["kind"].constantize.find(res["id"]) + end + end + def lines if metadatas.blank? workbench ? workbench.lines : associated_lines @@ -249,7 +271,8 @@ class Referential < ApplicationModel stop_area_referential: from.stop_area_referential, created_from: from, objectid_format: from.objectid_format, - metadatas: from.metadatas.map { |m| ReferentialMetadata.new_from(m, organisation) } + metadatas: from.metadatas.map { |m| ReferentialMetadata.new_from(m, organisation) }, + ready: false ) end @@ -300,12 +323,13 @@ class Referential < ApplicationModel before_create :create_schema after_create :clone_schema, if: :created_from + after_create :active!, unless: :created_from before_destroy :destroy_schema before_destroy :destroy_jobs def referential_read_only? - in_referential_suite? || archived? + !ready? || in_referential_suite? || archived? end def in_referential_suite? @@ -375,7 +399,7 @@ class Referential < ApplicationModel query = "select distinct(public.referential_metadata.referential_id) FROM public.referential_metadata, unnest(line_ids) line, LATERAL unnest(periodes) period WHERE public.referential_metadata.referential_id - IN (SELECT public.referentials.id FROM public.referentials WHERE referentials.workbench_id = #{workbench_id} and referentials.archived_at is null and referentials.referential_suite_id is null #{not_myself}) + IN (SELECT public.referentials.id FROM public.referentials WHERE referentials.workbench_id = #{workbench_id} and referentials.archived_at is null and referentials.referential_suite_id is null #{not_myself} AND referentials.failed_at IS NULL) AND line in (#{line_ids.join(',')}) and (#{periods_query});" self.class.connection.select_values(query).map(&:to_i) @@ -449,6 +473,7 @@ class Referential < ApplicationModel end def destroy_schema + return unless ActiveRecord::Base.connection.schema_names.include?(slug) Apartment::Tenant.drop slug end @@ -527,6 +552,46 @@ class Referential < ApplicationModel ready.not_merged.not_in_referential_suite end + ### STATE + + def state + return :failed if failed_at.present? + return :archived if archived_at.present? + ready? ? :active : :pending + end + + def pending! + update ready: false, failed_at: nil, archived_at: nil + end + + def failed! + update ready: false, failed_at: Time.now, archived_at: nil + end + + def active! + update ready: true, failed_at: nil, archived_at: nil + end + + def archived! + update failed_at: nil, archived_at: Time.now + end + + STATES.each do |s| + define_method "#{s}?" do + state == s + end + end + + def pending_while + vals = attributes.slice(*%w(ready archived_at failed_at)) + pending! + begin + yield + ensure + update vals + end + end + private def lock_table diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb index 4179ba312..cb8ad3630 100644 --- a/app/models/referential_cloning.rb +++ b/app/models/referential_cloning.rb @@ -54,7 +54,7 @@ class ReferentialCloning < ApplicationModel end def dump_command - "PGPASSWORD=#{password} pg_dump --host #{host} --username #{username} --schema=#{source_schema} #{database}" + "PGPASSWORD='#{password}' pg_dump --host #{host} --username #{username} --schema=#{source_schema} #{database}" end def sed_command @@ -62,7 +62,7 @@ class ReferentialCloning < ApplicationModel end def restore_command - "PGPASSWORD=#{password} psql -q --host #{host} --username #{username} #{database}" + "PGPASSWORD='#{password}' psql -q --host #{host} --username #{username} #{database}" end def clean diff --git a/app/models/workbench.rb b/app/models/workbench.rb index ef0b2eaa4..1bca91c56 100644 --- a/app/models/workbench.rb +++ b/app/models/workbench.rb @@ -38,7 +38,6 @@ class Workbench < ApplicationModel .referentials .joins(:metadatas) .where(['referential_metadata.line_ids && ARRAY[?]::bigint[]', line_ids]) - .ready .not_in_referential_suite end end @@ -52,6 +51,20 @@ class Workbench < ApplicationModel where(name: DEFAULT_WORKBENCH_NAME).last end + # XXX + # def import_compliance_control_set + # import_compliance_control_set_id && ComplianceControlSet.find(import_compliance_control_set_id) + # end + + def compliance_control_set key + id = (owner_compliance_control_set_ids || {})[key.to_s] + id.present? && ComplianceControlSet.find(id) + end + + def compliance_control_set_ids=(compliance_control_set_ids) + self.owner_compliance_control_set_ids = (owner_compliance_control_set_ids || {}).merge compliance_control_set_ids + end + private def initialize_output diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb index 3e8409634..6bb03c7fa 100644 --- a/app/models/workgroup.rb +++ b/app/models/workgroup.rb @@ -1,6 +1,7 @@ class Workgroup < ApplicationModel belongs_to :line_referential belongs_to :stop_area_referential + belongs_to :owner, class_name: "Organisation" has_many :workbenches has_many :calendars @@ -16,6 +17,8 @@ class Workgroup < ApplicationModel has_many :custom_fields + accepts_nested_attributes_for :workbenches + def custom_fields_definitions Hash[*custom_fields.map{|cf| [cf.code, cf]}.flatten] end @@ -23,4 +26,35 @@ class Workgroup < ApplicationModel def has_export? export_name export_types.include? export_name end + + def all_compliance_control_sets + %i(after_import + after_import_by_workgroup + before_merge + before_merge_by_workgroup + after_merge + after_merge_by_workgroup + automatic_by_workgroup + ) + end + + def compliance_control_sets_by_workgroup + compliance_control_sets_labels all_compliance_control_sets.grep(/by_workgroup$/) + end + + def compliance_control_sets_by_workbench + compliance_control_sets_labels all_compliance_control_sets.grep_v(/by_workgroup$/) + end + + def import_compliance_control_sets + compliance_control_sets_labels all_compliance_control_sets.grep(/^after_import/) + end + + private + def compliance_control_sets_labels(keys) + keys.inject({}) do |h, k| + h[k] = "workgroups.compliance_control_sets.#{k}".t.capitalize + h + end + end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index 33d88660c..36f14437a 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -100,7 +100,7 @@ class ApplicationPolicy # ------- def referential - @referential ||= current_referential || record_referential + @referential ||= current_referential || record_referential end def record_referential diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index f5c2d7c08..4b8b40b36 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -5,6 +5,10 @@ class ReferentialPolicy < ApplicationPolicy end end + def browse? + record.active? || record.archived? + end + def create? user.has_permission?('referentials.create') end @@ -18,7 +22,7 @@ class ReferentialPolicy < ApplicationPolicy end def clone? - !record.in_referential_suite? && create? + record.ready? && !record.in_referential_suite? && create? end def validate? @@ -30,7 +34,7 @@ class ReferentialPolicy < ApplicationPolicy end def unarchive? - record.archived? && !record.merged? && organisation_match? && user.has_permission?('referentials.update') + record.ready? && record.archived? && !record.merged? && organisation_match? && user.has_permission?('referentials.update') end def common_lines? @@ -38,4 +42,7 @@ class ReferentialPolicy < ApplicationPolicy true end + def referential_read_only? + record.referential_read_only? + end end diff --git a/app/policies/workbench_policy.rb b/app/policies/workbench_policy.rb index 7b925e91a..9f2279c38 100644 --- a/app/policies/workbench_policy.rb +++ b/app/policies/workbench_policy.rb @@ -6,6 +6,6 @@ class WorkbenchPolicy < ApplicationPolicy end def update? - true + user.has_permission?('workbenches.update') end end diff --git a/app/policies/workgroup_policy.rb b/app/policies/workgroup_policy.rb new file mode 100644 index 000000000..01914bb51 --- /dev/null +++ b/app/policies/workgroup_policy.rb @@ -0,0 +1,19 @@ +class WorkgroupPolicy < ApplicationPolicy + class Scope < Scope + def resolve + scope + end + end + + def create? + false + end + + def desrtroy? + false + end + + def update? + record.owner == user.organisation + end +end diff --git a/app/services/referential_consolidated.rb b/app/services/referential_consolidated.rb new file mode 100644 index 000000000..465eab405 --- /dev/null +++ b/app/services/referential_consolidated.rb @@ -0,0 +1,124 @@ +class ReferentialConsolidated + attr_reader :params + + def initialize vehicle_journeys, params + @vehicle_journeys = vehicle_journeys + @params = params + end + + def paginated_lines + @paginated_lines ||= begin + line_ids = @vehicle_journeys.joins(route: :line).pluck('lines.id') + lines = Chouette::Line.where(id: line_ids).order(:name) + lines.paginate page: params[:page], per_page: params[:per_page] || 10 + end + end + + def lines + @lines ||= paginated_lines.to_a.map {|l| Line.new(self, l, @vehicle_journeys, params) } + end + + def _should_highlight? + return false unless params[:q].present? + keys = params[:q].keys - ["stop_areas"] + params[:q].values_at(*keys).each do |value| + if value.is_a?(Hash) + return true if value.values.any?(&:present?) + elsif value.is_a?(Array) + return true if value.any?(&:present?) + else + if value.present? + return true + end + end + end + false + end + + def should_highlight? + if @should_highlight.nil? + @should_highlight = _should_highlight? + end + @should_highlight + end + + class Base + extend Forwardable + attr_reader :params + attr_reader :parent + attr_reader :ar_model + + def initialize parent, ar_model, vehicle_journeys, params + @parent = parent + @ar_model = ar_model + @all_vehicle_journeys = vehicle_journeys + @params = params + end + + def should_highlight? + parent.should_highlight? + end + end + + class Line < Base + delegate name: :ar_model + delegate id: :ar_model + + def routes + @routes ||= begin + ar_model.routes.order(:name).map {|r| Route.new(self, r, @all_vehicle_journeys, params) } + end + end + end + + class Route < Base + def_delegators :ar_model, :name, :id, :time_tables, :purchase_windows, :stop_area_ids + + def vehicle_journeys + @vehicle_journeys ||= begin + ar_model.vehicle_journeys.map {|vj| VehicleJourney.new(self, vj, @all_vehicle_journeys, params) } + end + end + + def highlighted_journeys + @all_vehicle_journeys.joins(:journey_pattern).where(route_id: self.id) + end + + def highlighted_count + highlighted_journeys.count + end + + def highlighted? + matching_stop_areas = params[:q] && params[:q]["stop_areas"] && (params[:q]["stop_areas"].values & self.stop_area_ids.map(&:to_s)).present? + (should_highlight? || matching_stop_areas) && highlighted_journeys.exists? + end + + def stop_points + @stop_points ||= ar_model.stop_points.map {|sp| StopPoint.new(self, sp, @all_vehicle_journeys, params) } + end + end + + class VehicleJourney < Base + def_delegators :ar_model, :id, :published_journey_name, :journey_pattern, :time_tables, :purchase_windows, :vehicle_journey_at_stops, :time_table_ids, :purchase_window_ids, :route + + def highlighted? + should_highlight? && @all_vehicle_journeys.where(id: self.id).exists? + end + + def has_purchase_window? purchase_window + purchase_window_ids.include?(purchase_window.id) + end + + def has_time_table? time_table + time_table_ids.include?(time_table.id) + end + end + + class StopPoint < Base + def_delegators :ar_model, :id, :arrival_time, :departure_time, :name, :stop_area, :stop_area_id + + def highlighted? + params[:q] && params[:q]["stop_areas"] && params[:q]["stop_areas"].values.any?{|v| v.to_s == stop_area_id.to_s} + end + end +end diff --git a/app/services/route_way_cost_calculator.rb b/app/services/route_way_cost_calculator.rb index d41a2e59a..ca47a6772 100644 --- a/app/services/route_way_cost_calculator.rb +++ b/app/services/route_way_cost_calculator.rb @@ -8,5 +8,7 @@ class RouteWayCostCalculator way_costs = TomTom.matrix(way_costs) way_costs = WayCostCollectionJSONSerializer.dump(way_costs) @route.update(costs: way_costs) + rescue TomTom::Errors::MatrixRemoteError => e + Rails.logger.error "TomTom::Matrix server error: #{e}" end end diff --git a/app/views/companies/edit.html.slim b/app/views/companies/edit.html.slim index faa88f829..c85bef0ec 100644 --- a/app/views/companies/edit.html.slim +++ b/app/views/companies/edit.html.slim @@ -1,3 +1,8 @@ - breadcrumb :company, @company - page_header_content_for @company -= render 'form'
\ No newline at end of file + +.page_content + .container-fluid + .row + .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1 + = render 'form' diff --git a/app/views/companies/new.html.slim b/app/views/companies/new.html.slim index 1747b8e10..6cc32130d 100644 --- a/app/views/companies/new.html.slim +++ b/app/views/companies/new.html.slim @@ -1,6 +1,7 @@ - breadcrumb :companies, @line_referential + .page_content .container-fluid .row .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1 - = render 'form'
\ No newline at end of file + = render 'form' diff --git a/app/views/companies/show.html.slim b/app/views/companies/show.html.slim index 8960b92dd..6335d88da 100644 --- a/app/views/companies/show.html.slim +++ b/app/views/companies/show.html.slim @@ -6,7 +6,7 @@ .container-fluid .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 - - attributes = { t('id_codif') => @company.try(:objectid).try(:local_id), + - attributes = { t('id_codif') => @company.get_objectid.try(:short_id), Chouette::Company.human_attribute_name(:phone) => @company.phone, Chouette::Company.human_attribute_name(:email) => @company.email, Chouette::Company.human_attribute_name(:url) => @company.url } diff --git a/app/views/compliance_check_sets/show.html.slim b/app/views/compliance_check_sets/show.html.slim index 4e1a8e2f9..bf4642b21 100644 --- a/app/views/compliance_check_sets/show.html.slim +++ b/app/views/compliance_check_sets/show.html.slim @@ -9,6 +9,7 @@ = definition_list( t('metadatas'), { I18n.t("compliance_check_sets.show.metadatas.referential") => (@compliance_check_set.referential.nil? ? '' : link_to(@compliance_check_set.referential.name, referential_path(@compliance_check_set.referential)) ), I18n.t("compliance_check_sets.show.metadatas.referential_type") => 'Jeu de données', + I18n.t("compliance_check_sets.show.metadatas.status") => import_status(@compliance_check_set.status, verbose: true), I18n.t("compliance_check_sets.show.metadatas.compliance_check_set_executed") => link_to(@compliance_check_set.name, executed_workbench_compliance_check_set_path(@compliance_check_set.workbench_id, @compliance_check_set)), I18n.t("compliance_check_sets.show.metadatas.compliance_control_owner") => @compliance_check_set.organisation.name, I18n.t("compliance_check_sets.show.metadatas.import") => '' }) diff --git a/app/views/compliance_control_sets/show.html.slim b/app/views/compliance_control_sets/show.html.slim index 729c1ce43..48c03d7c8 100644 --- a/app/views/compliance_control_sets/show.html.slim +++ b/app/views/compliance_control_sets/show.html.slim @@ -15,8 +15,9 @@ = render '/compliance_controls/filters' / compliance controls without block - = render_compliance_control_block - = render_compliance_controls(@direct_compliance_controls) + - unless params[:q].present? && @direct_compliance_controls.nil? + = render_compliance_control_block + = render_compliance_controls(@direct_compliance_controls) / compliance controls with block - if params[:q] && params[:q][:compliance_control_block_id_eq_any].try(:present?) diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim index 466695b5a..ce869ee4a 100644 --- a/app/views/dashboards/_dashboard.html.slim +++ b/app/views/dashboards/_dashboard.html.slim @@ -11,9 +11,9 @@ div = link_to '', workbench_path(workbench), class: ' fa fa-chevron-right pull-right', title: t('workbenches.index.offers.see') - - if workbench.referentials.present? + - if workbench.all_referentials.present? .list-group - - workbench.referentials.limit(5).each do |referential| + - workbench.all_referentials.limit(5).each do |referential| = link_to referential.name, referential_path(referential), class: 'list-group-item' - else .panel-body diff --git a/app/views/devise/invitations/edit.html.slim b/app/views/devise/invitations/edit.html.slim index 7a22146c0..20c2f15c8 100644 --- a/app/views/devise/invitations/edit.html.slim +++ b/app/views/devise/invitations/edit.html.slim @@ -1,6 +1,5 @@ / PageHeader - -- content_for :page_header_title, t('.title') +- content_for :page_header_title, t('devise.registrations.edit.title') / PageContent .page_content @@ -16,4 +15,4 @@ = form.input :password, as: :password = form.input :password_confirmation, as: :password - = form.button :submit, value: t('devise.invitations.edit.submit_button'), class: 'btn-info btn-default formSubmitr', form: 'invitation_form' + = form.button :submit, value: t('actions.submit'), class: 'btn-info btn-default formSubmitr', form: 'invitation_form' diff --git a/app/views/devise/invitations/new.html.slim b/app/views/devise/invitations/new.html.slim index 87bfbf750..90f086c2b 100644 --- a/app/views/devise/invitations/new.html.slim +++ b/app/views/devise/invitations/new.html.slim @@ -1,10 +1,15 @@ -h2 = t('devise.invitations.new.header') +- content_for :page_header_title, t('devise.registrations.new.title') -= simple_form_for resource, as: resource_name, :url => invitation_path(resource_name), :html => {:method => :post, class: "form-horizontal"} do |form| - = form.input :organisation_id, :as => :hidden, input_html: { :value => current_organisation.id } +/ PageContent +.page_content + .container-fluid + .row + .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1 + = simple_form_for resource, as: resource_name, :url => invitation_path(resource_name), :html => {:method => :post, class: "form-horizontal", id: "new_user_form"} do |form| + = form.input :organisation_id, :as => :hidden, input_html: { :value => current_organisation.id } - - resource.class.invite_key_fields.each do |field| - = form.input field + - resource.class.invite_key_fields.each do |field| + = form.input field - .form-actions - = form.button :submit, value: t('devise.invitations.new.submit_button'), class: 'btn-info'
\ No newline at end of file + .form-actions + = form.button :submit, value: t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'new_user_form'
\ No newline at end of file diff --git a/app/views/import_resources/show.html.slim b/app/views/import_resources/show.html.slim new file mode 100644 index 000000000..7fd8b4456 --- /dev/null +++ b/app/views/import_resources/show.html.slim @@ -0,0 +1,52 @@ +- breadcrumb :import_resource, @import_resource + +.page_content.import_messages + .container-fluid + .row + .col-lg-12 + - metadata = { 'Bilan d\'import' => link_to(@import_resource.root_import.name, workbench_import_path(@import_resource.root_import.workbench, @import_resource.root_import) ), + 'Jeu de données associé' => ( @import_resource.referential.present? ? link_to(@import_resource.referential.name, referential_path(@import_resource.referential)) : '-' ) } + - metadata = metadata.update({t('.status') => import_status(@import_resource.status, verbose: true) }) + = definition_list t('metadatas'), metadata + + + .col-lg-12 + .error_messages + = render 'shared/iev_interfaces/messages', messages: @import_resource.messages + + + // XXX + //- if @import_resource.children.present? + - if @import_resource&.netex_import&.resources.present? + .col-lg-12 + h2 = t('.table_title') + .col-lg-12 + = t('.table_explanation') + .col-lg-12 + = table_builder_2 @import_resource.netex_import.resources.where(resource_type: :file), + [ \ + TableBuilderHelper::Column.new( \ + key: :name, \ + attribute: 'name', \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| import_resource_status(n.status) }, \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + name: 'Résultat des tests' , \ + attribute: Proc.new { |n| I18n.t('import_resources.index.metrics', n.metrics.deep_symbolize_keys) }, \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + name: 'Téléchargement' , \ + attribute: Proc.new { |n| '<i class="fa fa-download" aria-hidden="true"></i>'.html_safe }, \ + sortable: false, \ + link_to: lambda do |import_resource| \ + workbench_import_import_resource_import_messages_path(import_resource.import.workbench, import_resource.import, import_resource, format: 'csv' ) \ + end \ + ), \ + ], + cls: 'table has-search' diff --git a/app/views/imports/import/_gtf.html.slim b/app/views/imports/import/_gtf.html.slim new file mode 100644 index 000000000..e50b45888 --- /dev/null +++ b/app/views/imports/import/_gtf.html.slim @@ -0,0 +1,43 @@ +- breadcrumb :gtfs_import, @workbench, @import + +.row + .col-lg-6.col-md-6.col-sm-12.col-xs-12 + - metadata = {t('.status') => import_status(@import.status, verbose: true) } + - metadata = metadata.update({t('.referential') => @import.referential ? link_to(@import.referential.name, [@import.referential]) : "-" }) + = definition_list t('metadatas'), metadata + +.col-lg-12 + .error_messages + = render 'shared/iev_interfaces/messages', messages: @import.main_resource.messages + +- if @import.resources.any? + .col-lg-12 + = table_builder_2 @import.resources, + [ \ + TableBuilderHelper::Column.new( \ + name: t('imports.show.referential_name'), \ + attribute: 'name', \ + sortable: false, \ + link_to: lambda do |item| \ + referential_path(item.referential) if item.referential.present? \ + end \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| import_status(n.status, verbose: true, default_status: :pending) }, \ + sortable: false, \ + link_to: lambda do |item| \ + item.netex_import.present? ? [@import.workbench, item.netex_import] : [@import.workbench, @import, item] \ + end \ + )\ + ], + cls: 'table', + overhead: [ \ + {}, \ + {}, \ + { \ + title: I18n.t('imports.show.summary').html_safe, \ + width: controls.size, \ + cls: 'overheaded-default colspan="2"' \ + } \ + ] diff --git a/app/views/imports/import/_netex.html.slim b/app/views/imports/import/_netex.html.slim new file mode 100644 index 000000000..ab0ed20d7 --- /dev/null +++ b/app/views/imports/import/_netex.html.slim @@ -0,0 +1,45 @@ +- breadcrumb :netex_import, @workbench, @import + +.row + .col-lg-6.col-md-6.col-sm-12.col-xs-12 + - metadata = {Import::Base.tmf(:status) => import_status(@import.status, verbose: true) } + - metadata = metadata.update({Import::Base.tmf(:referential) => @import.referential ? link_to(@import.referential.name, [@import.referential]) : "-" }) + = definition_list t('metadatas'), metadata + +.col-lg-12 + .error_messages + = render 'shared/iev_interfaces/messages', messages: @import.main_resource.messages + +- if @import.resources.present? + .col-lg-12 + h2 = t('imports.show.netex.table_title') + .col-lg-12 + = t('imports.show.netex.table_explanation') + .col-lg-12 + = table_builder_2 @import.resources.where(resource_type: :file), + [ \ + TableBuilderHelper::Column.new( \ + key: :name, \ + attribute: 'name', \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| import_resource_status(n.status) }, \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + name: t('imports.show.table.test_results') , \ + attribute: Proc.new { |n| I18n.t('import_resources.index.metrics', n.metrics.deep_symbolize_keys) }, \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + name: t('imports.show.table.download') , \ + attribute: Proc.new { |n| '<i class="fa fa-download" aria-hidden="true"></i>'.html_safe }, \ + sortable: false, \ + link_to: lambda do |import_resource| \ + workbench_import_import_resource_import_messages_path(import_resource.import.workbench, import_resource.import, import_resource, format: 'csv' ) \ + end \ + ), \ + ], + cls: 'table has-search' diff --git a/app/views/imports/import/_workbench.html.slim b/app/views/imports/import/_workbench.html.slim new file mode 100644 index 000000000..cbdf604c2 --- /dev/null +++ b/app/views/imports/import/_workbench.html.slim @@ -0,0 +1,55 @@ +- breadcrumb :import, @workbench, @import + +.row + .col-lg-6.col-md-6.col-sm-12.col-xs-12 + - metadata = { t('.data_recovery') => '-', t('imports.show.filename') => @import.try(:file_identifier)} + - metadata = metadata.update({Import::Base.tmf(:status) => import_status(@import.status, verbose: true) }) + = definition_list t('metadatas'), metadata + +.col-lg-12 + .error_messages + = render 'shared/iev_interfaces/messages', messages: @import.messages + +ruby: + controls = @workbench.workgroup.import_compliance_control_sets.map do |key, label| + TableBuilderHelper::Column.new( + name: label, + attribute: Proc.new { |n| n.workbench.compliance_control_set(key).present? ? import_status(n.workbench_import_check_set(key)&.status, verbose: true, default_status: (n.status == "ERROR" ? :aborted : :pending)) : '-' }, + sortable: false, + link_to: lambda do |item| + item.workbench_import_check_set(key).present? && [@import.workbench, item.workbench_import_check_set(key)] + end + ) + end + +- if @import.resources.any? + .col-lg-12 + = table_builder_2 @import.resources, + [ \ + TableBuilderHelper::Column.new( \ + name: t('imports.show.referential_name'), \ + attribute: 'name', \ + sortable: false, \ + link_to: lambda do |item| \ + referential_path(item.referential) if item.referential.present? \ + end \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| import_status(n.netex_import&.status || n.status, verbose: true, default_status: :pending) }, \ + sortable: false, \ + link_to: lambda do |item| \ + item.netex_import.present? ? [@import.workbench, item.netex_import] : [@import.workbench, @import, item] \ + end \ + ), *controls \ + ], + cls: 'table', + overhead: [ \ + {}, \ + {}, \ + controls.present? ? { \ + title: I18n.t('imports.show.summary').html_safe, \ + width: controls.size, \ + cls: "overheaded-default colspan='#{controls.size}'" \ + } : nil \ + ].compact diff --git a/app/views/imports/show.html.slim b/app/views/imports/show.html.slim index 9d0a6423d..fb83e9a06 100644 --- a/app/views/imports/show.html.slim +++ b/app/views/imports/show.html.slim @@ -1,60 +1,5 @@ -- breadcrumb :import, @workbench, @import - - page_header_content_for @import .page_content .container-fluid - .row - .col-lg-6.col-md-6.col-sm-12.col-xs-12 - = definition_list t('metadatas'), { t('.data_recovery') => '-', t('.filename') => @import.try(:file_identifier)} - - .row - .col-lg-12 - .error_messages - = render 'shared/iev_interfaces/messages', messages: @import.messages - - - if @import.children.any? - .row - .col-lg-12 - = table_builder_2 @import.children, - [ \ - TableBuilderHelper::Column.new( \ - name: t('.referential_name'), \ - attribute: 'name', \ - sortable: false, \ - link_to: lambda do |import| \ - referential_path(import.referential) if import.referential.present? \ - end \ - ), \ - TableBuilderHelper::Column.new( \ - key: :status, \ - attribute: Proc.new { |n| import_status(n.status) }, \ - sortable: false, \ - link_to: lambda do |import| \ - workbench_import_import_resources_path(import.workbench_id, import) \ - end \ - ), \ - TableBuilderHelper::Column.new( \ - name: t('.stif_control'), \ - attribute: '', \ - sortable: false, \ - ), \ - TableBuilderHelper::Column.new( \ - name: t('.organisation_control'), \ - attribute: '', \ - sortable: false, \ - ) \ - ], - cls: 'table', - overhead: [ \ - {}, \ - { \ - title: I18n.t('imports.show.results', count: @import.children_succeedeed, total: @import.children.count), \ - width: 1, \ - cls: "#{@import.import_status_css_class} full-border" \ - }, { \ - title: I18n.t('imports.show.summary').html_safe, \ - width: 2, \ - cls: 'overheaded-default colspan="2"' \ - } \ - ] + = render partial: "imports/#{@import.type.tableize.singularize}" diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index abf39c089..596627996 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -8,6 +8,8 @@ html lang=I18n.locale title = t('brandname') + = favicon_link_tag + = stylesheet_link_tag 'base' = stylesheet_link_tag 'application' diff --git a/app/views/layouts/navigation/_main_nav_left_content.html.slim b/app/views/layouts/navigation/_main_nav_left_content.html.slim index 0b55578a7..004ea9050 100644 --- a/app/views/layouts/navigation/_main_nav_left_content.html.slim +++ b/app/views/layouts/navigation/_main_nav_left_content.html.slim @@ -15,6 +15,9 @@ span = t('layouts.navbar.workbench_outputs.organisation') = link_to '#', class: 'list-group-item disabled' do span = t('layouts.navbar.workbench_outputs.workgroup') + - if policy(workbench.workgroup).edit? + = link_to [:edit, workbench.workgroup], class: 'list-group-item' do + span = t('layouts.navbar.workbench_outputs.edit_workgroup') .menu-item.panel .panel-heading @@ -36,7 +39,10 @@ span = t('activerecord.models.compliance_check_set.other').capitalize = link_to compliance_control_sets_path, class: 'list-group-item' do span = t('activerecord.models.compliance_control_set.other').capitalize - + - if policy(workbench).edit? + = link_to [:edit, workbench], class: 'list-group-item' do + span = t('workbenches.edit.link') + .menu-item.panel .panel-heading h4.panel-title @@ -62,3 +68,18 @@ .list-group = link_to stop_area_referential_stop_areas_path(workbench.stop_area_referential), class: "list-group-item" do span = Chouette::StopArea.t.capitalize + + .menu-item.panel + .panel-heading + h4.panel-title + = link_to '#miSix', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do + = t('layouts.navbar.configuration') + + #miSix.panel-collapse.collapse + .list-group + - if policy(workbench).edit? + = link_to [:edit, workbench], class: 'list-group-item' do + span = t('layouts.navbar.workbench_configuration') + - if policy(workbench.workgroup).edit? + = link_to [:edit, workbench.workgroup], class: 'list-group-item' do + span = t('layouts.navbar.workgroup_configuration') diff --git a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim index 9404eeae6..7bea0814e 100644 --- a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim +++ b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim @@ -70,10 +70,25 @@ .panel-heading h4.panel-title = link_to '#miSix', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do - = t('layouts.navbar.tools') + = t('layouts.navbar.configuration') #miSix.panel-collapse.collapse .list-group + - if policy(workbench).edit? + = link_to [:edit, workbench], class: 'list-group-item' do + span = t('layouts.navbar.workbench_configuration') + - if policy(workbench.workgroup).edit? + = link_to [:edit, workbench.workgroup], class: 'list-group-item' do + span = t('layouts.navbar.workgroup_configuration') + + .menu-item.panel + .panel-heading + h4.panel-title + = link_to '#miSeven', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do + = t('layouts.navbar.tools') + + #miSeven.panel-collapse.collapse + .list-group = link_to Rails.application.config.try(:portal_url), target: '_blank', class: 'list-group-item' do span span.fa.fa-2x.fa-circle diff --git a/app/views/layouts/navigation/_page_header.html.slim b/app/views/layouts/navigation/_page_header.html.slim index bdc4bdfed..1cac86c4a 100644 --- a/app/views/layouts/navigation/_page_header.html.slim +++ b/app/views/layouts/navigation/_page_header.html.slim @@ -1,5 +1,6 @@ - action_links = resource.action_links(params[:action]) rescue nil - action_links ||= decorated_collection.action_links(params[:action]) rescue nil +- action_links = nil if response.status != 200 .page_header .container-fluid .row diff --git a/app/views/referential_vehicle_journeys/_consolidated.html.slim b/app/views/referential_vehicle_journeys/_consolidated.html.slim new file mode 100644 index 000000000..4a1866e8a --- /dev/null +++ b/app/views/referential_vehicle_journeys/_consolidated.html.slim @@ -0,0 +1,49 @@ +.row.consolidated-view + - @consolidated.lines.each do |line| + = render partial: "consolidated_line", object: line + .col-md-12 + = new_pagination @consolidated.paginated_lines, 'pull-right' + +coffee: + $('a.toggle-timetables').click (e)-> + e.preventDefault() + $(e.target).toggleClass 'active' + $(e.target).parents('.table').find('.detailed-timetables').customToggle() + + $('a.toggle-purchase-windows').click (e)-> + e.preventDefault() + $(e.target).toggleClass 'active' + $(e.target).parents('.table').find('.detailed-purchase-windows').customToggle() + + $('.route').find('.togglable.hidden').each (i, e)-> + $e = $(e) + $e.removeClass 'hidden' + e.setAttribute 'data-original-height', $e.innerHeight() + e.setAttribute 'data-original-full-height', $e.outerHeight(true) + $e.css height: 0 + $e.addClass 'ready' + + $('a.toggle-route').click (e)-> + e.preventDefault() + $(e.currentTarget).toggleClass 'active' + tab = $(e.currentTarget).parents('.route').find('.vehicle-journeys') + tab.customToggle() + + $.fn.extend + customToggle: (propagate=true)-> + height = parseFloat this.attr('data-original-height') + fullHeight = parseFloat this.attr('data-original-full-height') + if this.hasClass 'open' + this.css height: 0 + this.removeClass 'open' + this.find('.togglable.open').customToggle(false) + this.find('a.active').removeClass 'active' + if propagate + for parent in this.parents(".togglable.open") + $(parent).height $(parent).height() - fullHeight + else + this.addClass 'open' + this.height height + if propagate + for parent in this.parents(".togglable.open") + $(parent).height $(parent).height() + fullHeight diff --git a/app/views/referential_vehicle_journeys/_consolidated_line.html.slim b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim new file mode 100644 index 000000000..c73c65961 --- /dev/null +++ b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim @@ -0,0 +1,119 @@ +.line.col-md-12 + .head + span + = Chouette::Line.ts + | + strong= consolidated_line.name + .routes + - consolidated_line.routes.each do |route| + .route + .head class="#{route.highlighted? ? 'highlighted' : ''}" + = link_to '#', class: 'toggle-route' do + span.sb.sb-route + | + = Chouette::Route.ts + | + strong= route.name + .pull-right + = route.highlighted_count + | + = Chouette::VehicleJourney.t + | + span.fa.fa-angle-up + .table.table-2entries.vehicle-journeys.hidden.togglable + .t2e-head.w20 + .th + div + strong= Chouette::VehicleJourney.tmf(:id) + div= Chouette::VehicleJourney.tmf(:name) + div= Chouette::VehicleJourney.tmf(:journey_pattern_id) + div + = link_to '#', class: 'toggle-purchase-windows detailed-timetables-bt' do + span.fa.fa-angle-up + = Chouette::PurchaseWindow.t + .detailed-purchase-windows.hidden.togglable + - route.purchase_windows.uniq.each do |tt| + div + p + = link_to [@referential, tt] do + span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')} + | + = tt.name + + p= tt.bounding_dates.split(' ').join(' > ') + div + = link_to '#', class: 'toggle-timetables detailed-timetables-bt' do + span.fa.fa-angle-up + = Chouette::TimeTable.t + + .detailed-timetables.hidden.togglable + - route.time_tables.uniq.each do |tt| + div + p + = link_to [@referential, tt] do + span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')} + | + = tt.display_day_types + + p= tt.bounding_dates.split(' ').join(' > ') + - prev_sp = nil + - route.stop_points.each do |sp| + ruby: + headline = vehicle_journey_stop_headline prev_sp, sp + prev_sp = sp + .td class="#{sp.highlighted? ? 'highlighted' : ''}" + div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '') + span + = sp.name + - if sp.stop_area.time_zone_formatted_offset + span.small + | + = "(#{sp.stop_area.time_zone_formatted_offset})" + .t2e-item-list.w80 + div + - route.vehicle_journeys.each do |journey| + .t2e-item class="#{journey.highlighted? ? 'highlighted' : ''}" + .th + div + strong= link_to journey.id, [@referential, journey.route.line, journey.route, :vehicle_journeys] + div + = link_to journey.published_journey_name, [@referential, journey.route.line, journey.route, :vehicle_journeys], title: journey.published_journey_name + div= journey.journey_pattern.get_objectid.short_id + div + - journey.purchase_windows[0..3].each do |tt| + span.vj_tt + = link_to [@referential, tt], target: :blank do + span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}" + - if journey.purchase_windows.size > 3 + span.vj_tt = "+ #{journey.purchase_windows.size - 3}" + .detailed-purchase-windows.hidden.togglable + - route.purchase_windows.uniq.each do |tt| + div class=(journey.has_purchase_window?(tt) ? 'active' : 'inactive') + div + - journey.time_tables[0..3].each do |tt| + span.vj_tt + = link_to [@referential, tt], target: :blank do + span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}" + - if journey.time_tables.size > 3 + span.vj_tt = "+ #{journey.time_tables.size - 3}" + .detailed-timetables.hidden.togglable + - route.time_tables.uniq.each do |tt| + div class=(journey.has_time_table?(tt) ? 'active' : 'inactive') + + - prev_sp = nil + - route.stop_points.each do |sp| + ruby: + headline = vehicle_journey_stop_headline prev_sp, sp + prev_sp = sp + vjas = journey.vehicle_journey_at_stops.where(stop_point_id: sp.id).last + .td class="#{vjas && sp.highlighted? ? 'highlighted' : ''} #{vjas.nil? ? 'disabled' : ''} #{headline.present? ? 'headlined' : ''}" + div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '') + - if vjas.present? + - if vjas.departure_time == vjas.arrival_time + = vjas.departure_time.l(format: "%H:%M") + - else + = vjas.arrival_time.l(format: "%H:%M") + | - + = vjas.departure_time.l(format: "%H:%M") + - else + | 00:00 diff --git a/app/views/referential_vehicle_journeys/_filters.html.slim b/app/views/referential_vehicle_journeys/_filters.html.slim index a6e289b97..31053c5ba 100644 --- a/app/views/referential_vehicle_journeys/_filters.html.slim +++ b/app/views/referential_vehicle_journeys/_filters.html.slim @@ -1,10 +1,20 @@ = search_form_for @q, url: referential_vehicle_journeys_path(@referential), html: {method: :get}, class: 'form form-filter' do |f| - .ffg-row + input type="hidden" name="display" value=params[:display] + .ffg-row.w85 .input-group.search_bar = f.search_field :published_journey_name_or_objectid_cont, placeholder: t('.published_journey_name_or_objectid'), class: 'form-control' span.input-group-btn button.btn.btn-default#search-btn type='submit' span.fa.fa-search + .ffg-row.w15 + - if has_feature?(:consolidated_offers) + .form-group + .btn-group + = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :list), class: 'btn btn-default ' + (params[:display] != "consolidated" ? 'active' : '') do + span.fa.fa-align-justify + = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :consolidated), class: 'btn btn-default ' + (params[:display] == "consolidated" ? 'active' : '') do + span.fa.fa-th-large + .ffg-row .form-group.per-page-select = I18n.t("simple_form.per_page") @@ -73,5 +83,5 @@ .actions - = link_to t('actions.erase'), referential_vehicle_journeys_path(@referential), class: 'btn btn-link' + = link_to t('actions.erase'), referential_vehicle_journeys_path(@referential, display: params[:display]), class: 'btn btn-link' = f.submit t('actions.filter'), class: 'btn btn-default' diff --git a/app/views/referential_vehicle_journeys/_list.html.slim b/app/views/referential_vehicle_journeys/_list.html.slim new file mode 100644 index 000000000..74f8238f8 --- /dev/null +++ b/app/views/referential_vehicle_journeys/_list.html.slim @@ -0,0 +1,49 @@ +.row + .col-lg-12 + .select_table + = table_builder_2 @vehicle_journeys, + [ \ + TableBuilderHelper::Column.new( \ + name: t('objectid'), \ + attribute: Proc.new { |n| n.get_objectid.short_id }, \ + sortable: false \ + ), \ + TableBuilderHelper::Column.new( \ + key: :published_journey_name, \ + attribute: 'published_journey_name', \ + link_to: lambda do |vehicle_journey| \ + vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \ + end, \ + sortable: true \ + ), \ + TableBuilderHelper::Column.new( \ + key: :line, \ + attribute: Proc.new {|v| v.route.line.name}, \ + sortable: true \ + ), \ + TableBuilderHelper::Column.new( \ + key: :route, \ + attribute: Proc.new {|v| v.route.name}, \ + sortable: true \ + ), \ + TableBuilderHelper::Column.new( \ + key: :departure_time, \ + attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \ + sortable: true \ + ), \ + [@starting_stop, @ending_stop].compact.map{|stop| \ + TableBuilderHelper::Column.new( \ + attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \ + sortable: false, \ + name: stop.name \ + )\ + }, \ + TableBuilderHelper::Column.new( \ + key: :arrival_time, \ + attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \ + sortable: true, \ + ), \ + ].flatten.compact, + cls: 'table has-filter has-search' + + = new_pagination @vehicle_journeys, 'pull-right' diff --git a/app/views/referential_vehicle_journeys/index.html.slim b/app/views/referential_vehicle_journeys/index.html.slim index 00f63cb65..d1d1dae07 100644 --- a/app/views/referential_vehicle_journeys/index.html.slim +++ b/app/views/referential_vehicle_journeys/index.html.slim @@ -9,55 +9,11 @@ = render 'filters' - if @vehicle_journeys.present? - .row - .col-lg-12 - .select_table - = table_builder_2 @vehicle_journeys, - [ \ - TableBuilderHelper::Column.new( \ - name: t('objectid'), \ - attribute: Proc.new { |n| n.get_objectid.short_id }, \ - sortable: false \ - ), \ - TableBuilderHelper::Column.new( \ - key: :published_journey_name, \ - attribute: 'published_journey_name', \ - link_to: lambda do |vehicle_journey| \ - vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \ - end, \ - sortable: true \ - ), \ - TableBuilderHelper::Column.new( \ - key: :line, \ - attribute: Proc.new {|v| v.route.line.name}, \ - sortable: true \ - ), \ - TableBuilderHelper::Column.new( \ - key: :route, \ - attribute: Proc.new {|v| v.route.name}, \ - sortable: true \ - ), \ - TableBuilderHelper::Column.new( \ - key: :departure_time, \ - attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \ - sortable: true \ - ), \ - [@starting_stop, @ending_stop].compact.map{|stop| \ - TableBuilderHelper::Column.new( \ - attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \ - sortable: false, \ - name: stop.name \ - )\ - }, \ - TableBuilderHelper::Column.new( \ - key: :arrival_time, \ - attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \ - sortable: true, \ - ), \ - ].flatten.compact, - cls: 'table has-filter has-search' + - if params[:display] == "consolidated" && has_feature?(:consolidated_offers) + = render partial: "consolidated" + - else + = render partial: "list" - = new_pagination @vehicle_journeys, 'pull-right' - unless @vehicle_journeys.any? .row.mt-xs diff --git a/app/views/referentials/_filters.html.slim b/app/views/referentials/_filters.html.slim index 190e70ebe..ebaefb0f2 100644 --- a/app/views/referentials/_filters.html.slim +++ b/app/views/referentials/_filters.html.slim @@ -11,13 +11,15 @@ = f.label Chouette::Line.human_attribute_name(:transport_mode), required: false, class: 'control-label' = f.input :transport_mode_eq_any, collection: @referential.lines.pluck(:transport_mode).uniq.compact, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_mode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' } - .form-group.togglable class=filter_item_class(params[:q], :network_id_eq_any) - = f.label t('activerecord.attributes.referential.networks'), required: false, class: 'control-label' - = f.input :network_id_eq_any, collection: LineReferential.first.networks.order('name').pluck(:id), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>#{LineReferential.first.networks.find(l).name}</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' } + - if (network_ids = @referential.lines.pluck(:network_id).uniq.compact).size > 1 + .form-group.togglable class=filter_item_class(params[:q], :network_id_eq_any) + = f.label t('activerecord.attributes.referential.networks'), required: false, class: 'control-label' + = f.input :network_id_eq_any, collection: network_ids, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>#{Chouette::Network.find(l).name}</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' } - .form-group.togglable class=filter_item_class(params[:q], :company_id_eq_any) - = f.label t('activerecord.attributes.referential.companies'), required: false, class: 'control-label' - = f.input :company_id_eq_any, collection: LineReferential.first.companies.order('name').pluck(:id), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>#{LineReferential.first.companies.find(l).name}</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' } + - if (company_ids = @referential.lines.pluck(:company_id).uniq.compact).size > 1 + .form-group.togglable class=filter_item_class(params[:q], :company_id_eq_any) + = f.label t('activerecord.attributes.referential.companies'), required: false, class: 'control-label' + = f.input :company_id_eq_any, collection: company_ids, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>#{Chouette::Company.find(l).name}</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' } .actions = link_to t('actions.erase'), @workbench, class: 'btn btn-link' diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim index 3cdcff63b..9785c074d 100644 --- a/app/views/referentials/show.html.slim +++ b/app/views/referentials/show.html.slim @@ -6,88 +6,100 @@ .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 - attributes = {} - - 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(:state)] = referential_state(@referential) 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(: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? - .row - .col-lg-12 - = render 'filters' + - unless @referential.ready? + - if operation = @referential.last_operation + .jumbotron + = import_status(operation.status) + - url = operation.is_a?(Import::Base) ? [operation.workbench, operation.parent || operation] : [@referential, operation] + = link_to url do + | + span + strong= operation.try(:name) || operation.created_at.l(format: :short) + | + span= "(#{operation.class.ts})" - - if @reflines.any? - .row - .col-lg-12 - / ID Codif, nom court, nom de la ligne, réseau, mode, transporteur principal, actions = [show, edit_notes] - = table_builder_2 @reflines, - [ \ - TableBuilderHelper::Column.new( \ - name: t('id_codif'), \ - attribute: Proc.new { |n| n.get_objectid.short_id }, \ - sortable: false \ - ), \ - TableBuilderHelper::Column.new( \ - key: :number, \ - attribute: 'number' \ - ), \ - TableBuilderHelper::Column.new( \ - key: :name, \ - attribute: 'name', \ - link_to: lambda do |line| \ - referential_line_path(@referential, line) \ - end \ - ), \ - TableBuilderHelper::Column.new( \ - key: :status, \ - attribute: Proc.new { |n| line_status(n.status) } \ - ), \ - TableBuilderHelper::Column.new( \ - key: :transport_mode, \ - attribute: Proc.new { |n| n.transport_mode ? t("enumerize.transport_mode.#{n.transport_mode}") : '' }, \ - ), \ - TableBuilderHelper::Column.new( \ - key: 'networks.name', \ - attribute: Proc.new { |n| n.try(:network).try(:name) } \ - ), \ - TableBuilderHelper::Column.new( \ - key: 'companies.name', \ - attribute: Proc.new { |n| n&.company&.name || "-" } \ - ) \ - ], - cls: 'table has-filter has-search', - action: :index + - else + - if params[:q].present? or @reflines.any? + .row + .col-lg-12 + = render 'filters' + - if @reflines.any? + .row + .col-lg-12 + / ID Codif, nom court, nom de la ligne, réseau, mode, transporteur principal, actions = [show, edit_notes] + = table_builder_2 @reflines, + [ \ + TableBuilderHelper::Column.new( \ + name: t('id_codif'), \ + attribute: Proc.new { |n| n.get_objectid.short_id }, \ + sortable: false \ + ), \ + TableBuilderHelper::Column.new( \ + key: :number, \ + attribute: 'number' \ + ), \ + TableBuilderHelper::Column.new( \ + key: :name, \ + attribute: 'name', \ + link_to: lambda do |line| \ + referential_line_path(@referential, line) \ + end \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| line_status(n.status) } \ + ), \ + TableBuilderHelper::Column.new( \ + key: :transport_mode, \ + attribute: Proc.new { |n| n.transport_mode ? t("enumerize.transport_mode.#{n.transport_mode}") : '' }, \ + ), \ + TableBuilderHelper::Column.new( \ + key: 'networks.name', \ + attribute: Proc.new { |n| n.try(:network).try(:name) } \ + ), \ + TableBuilderHelper::Column.new( \ + key: 'companies.name', \ + attribute: Proc.new { |n| n&.company&.name || "-" } \ + ) \ + ], + cls: 'table has-filter has-search', + action: :index - = new_pagination @reflines, 'pull-right' + = new_pagination @reflines, 'pull-right' - - unless @reflines.any? - .row.mt-xs - .col-lg-12 - = replacement_msg t('referential_lines.search_no_results') + - unless @reflines.any? + .row.mt-xs + .col-lg-12 + = replacement_msg t('referential_lines.search_no_results') - = referential_overview resource + = referential_overview resource -/ Modal(s) -= modalbox 'purgeModal' do - = simple_form_for [@referential, CleanUp.new] do |f| - .modal-header - h4.modal-title #{t('simple_form.labels.clean_up.title')} - .modal-body - .container-fluid - .row - .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 - = f.input :date_type, as: :radio_buttons, label: false + / Modal(s) + = modalbox 'purgeModal' do + = simple_form_for [@referential, CleanUp.new] do |f| + .modal-header + h4.modal-title #{t('simple_form.labels.clean_up.title')} + .modal-body + .container-fluid + .row + .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 + = f.input :date_type, as: :radio_buttons, label: false - .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 - label.control-label.begin_date = t('titles.clean_up.begin_date') - label.control-label.end_date.hidden = t('titles.clean_up.end_date') - = f.input :begin_date, as: :date, label: false, wrapper_html: { class: 'date smart_date' } + .col-lg-8.col-ld-offset-2.col-md-8.col-md-offset-2.col-sm-8.col-sm-offset-2.col-xs-12 + label.control-label.begin_date = t('titles.clean_up.begin_date') + label.control-label.end_date.hidden = t('titles.clean_up.end_date') + = f.input :begin_date, as: :date, label: false, wrapper_html: { class: 'date smart_date' } - = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), wrapper_html: { class: 'date cleanup_end_date_wrapper smart_date', id: "end_date" } + = f.input :end_date, as: :date, label: t('titles.clean_up.end_date'), wrapper_html: { class: 'date cleanup_end_date_wrapper smart_date', id: "end_date" } - .modal-footer - button.btn.btn-link type='button' data-dismiss='modal' #{t('cancel')} - - unless policy(@referential).referential_read_only? - = f.button :submit, t('actions.clean_up') , class: 'btn btn-primary' + .modal-footer + button.btn.btn-link type='button' data-dismiss='modal' #{t('cancel')} + - unless policy(@referential).referential_read_only? + = f.button :submit, t('actions.clean_up') , class: 'btn btn-primary' diff --git a/app/views/routes/show.html.slim b/app/views/routes/show.html.slim index aea824a89..2218bd85f 100644 --- a/app/views/routes/show.html.slim +++ b/app/views/routes/show.html.slim @@ -30,7 +30,7 @@ key: :name, \ attribute: Proc.new { |s| content_tag :span, s.stop_area&.name, class: s.stop_area&.area_type }, \ link_to: lambda do |stop_point| \ - referential_stop_area_path(@referential, stop_point.stop_area) \ + stop_area_referential_stop_area_path(stop_point.stop_area.referential, stop_point.stop_area) \ end \ ), \ TableBuilderHelper::Column.new( \ diff --git a/app/views/shared/_development_toolbar.html.slim b/app/views/shared/_development_toolbar.html.slim index 836066b3d..1d45c41d0 100644 --- a/app/views/shared/_development_toolbar.html.slim +++ b/app/views/shared/_development_toolbar.html.slim @@ -1,4 +1,4 @@ -- if Rails.application.config.development_toolbar +- if Rails.application.config.development_toolbar && current_user = modalbox 'development-toolbar' do = form_tag development_toolbar_update_settings_path, authenticity_token: true do .modal-header diff --git a/app/views/workbenches/_filters.html.slim b/app/views/workbenches/_filters.html.slim index c9dd13d96..ffac2d736 100644 --- a/app/views/workbenches/_filters.html.slim +++ b/app/views/workbenches/_filters.html.slim @@ -11,11 +11,11 @@ = f.label t('activerecord.models.line.one').upcase, required: false, class: 'control-label' = f.input :associated_lines_id_eq, as: :select, collection: @workbench.lines.includes(:company).order(:name), input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': t('referentials.filters.line') }, label: false, label_method: :display_name, wrapper_html: { class: 'select2ed'} - .form-group.togglable class=filter_item_class(params[:q], :archived_at_not_null) + .form-group.togglable class=filter_item_class(params[:q], :state) = f.label Referential.human_attribute_name(:status), required: false, class: 'control-label' .form-group.checkbox_list - = f.input :archived_at_not_null, label: ("<span>#{t('activerecord.attributes.referential.archived_at')}<span class='fa fa-archive'></span></span>").html_safe, as: :boolean, wrapper_html: { class: 'checkbox-wrapper' } - = f.input :archived_at_null, label: ("<span>#{t('activerecord.attributes.referential.archived_at_null')}<span class='sb sb-lg sb-preparing'></span></span>").html_safe, as: :boolean, wrapper_html: { class: 'checkbox-wrapper' } + - Referential::STATES.each do |s| + = f.input "state[#{s}]", input_html: {checked: (params[:q] && params[:q][:state] && params[:q][:state][s]) == "1"}, label: ("<span>#{"referentials.states.#{s}".t}#{icon_for_referential_state(s)}</span>").html_safe, as: :boolean, wrapper_html: { class: 'checkbox-wrapper' } .form-group.togglable class=filter_item_class(params[:q], :organisation_name_eq_any) = f.label t('activerecord.models.organisation.one'), required: false, class: 'control-label' diff --git a/app/views/workbenches/_form.html.slim b/app/views/workbenches/_form.html.slim index 534a5f378..c7b6fd4f3 100644 --- a/app/views/workbenches/_form.html.slim +++ b/app/views/workbenches/_form.html.slim @@ -1,9 +1,10 @@ -= simple_form_for @workbench, html: { class: 'form-horizontal', id: 'workbench_form' }, wrapper: :horizontal_form do |f| += title_tag t('activerecord.models.compliance_control_set.other') + += simple_form_for @workbench, html: { class: 'form-horizontal', id: 'workbench_form' }, wrapper: :horizontal_form, title: "prout" do |f| .row .col-lg-12 - = f.input :import_compliance_control_set_id, as: :select, collection: current_organisation.compliance_control_sets, value_method: :id - = f.input :merge_compliance_control_set_id, as: :select, collection: current_organisation.compliance_control_sets, value_method: :id - - .separator + = f.fields_for :compliance_control_set_ids do |ff| + - @workbench.workgroup.compliance_control_sets_by_workbench.each do |cc, label| + = ff.input cc, as: :select, collection: current_organisation.compliance_control_sets, value_method: :id, label: label, selected: @workbench.compliance_control_set(cc).try(:id).try(:to_s), include_blank: true = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'workbench_form' diff --git a/app/views/workbenches/edit.html.slim b/app/views/workbenches/edit.html.slim index 893024490..0774610e1 100644 --- a/app/views/workbenches/edit.html.slim +++ b/app/views/workbenches/edit.html.slim @@ -1,4 +1,4 @@ -- breadcrumb @workbench +- breadcrumb :workbench_configure, @workbench - page_header_content_for @workbench .page_content diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim index 7dd1583fa..213c9e5f2 100644 --- a/app/views/workbenches/show.html.slim +++ b/app/views/workbenches/show.html.slim @@ -34,7 +34,7 @@ TableBuilderHelper::Column.new( \ key: :archived_at, \ name: Referential.tmf('status'), \ - attribute: Proc.new {|w| w.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} \ + attribute: Proc.new {|w| "<a href='' title='#{"referentials.states.#{w.state}".t}'>#{icon_for_referential_state(w.state)}</a>".html_safe} \ ), \ TableBuilderHelper::Column.new( \ key: :organisation, \ @@ -62,7 +62,10 @@ attribute: Proc.new {|w| w.merged_at ? l(w.merged_at, format: :short) : '-'} \ ) \ ], - selectable: ->(ref){ @workbench.referentials.include?(ref) }, + selectable: ->(ref) { \ + @workbench.referentials.include?(ref) && \ + !ref.pending? \ + }, cls: 'table has-filter has-search', action: :index diff --git a/app/views/workgroups/_form.html.slim b/app/views/workgroups/_form.html.slim new file mode 100644 index 000000000..52d1faca8 --- /dev/null +++ b/app/views/workgroups/_form.html.slim @@ -0,0 +1,17 @@ += title_tag t('activerecord.models.compliance_control_set.other') + += simple_form_for @workgroup, html: { class: 'form-horizontal', id: 'workgroup_form' }, wrapper: :horizontal_form do |f| + table.table + thead + th + - @workgroup.compliance_control_sets_by_workgroup.values.each do |cc| + th= cc + - @workgroup.workbenches.each_with_index do |w,i| + tr + th= w.organisation.name + - @workgroup.compliance_control_sets_by_workgroup.keys.each do |cc| + td + = hidden_field_tag "workgroup[workbenches_attributes][#{i}][id]", w.id + = select_tag "workgroup[workbenches_attributes][#{i}][compliance_control_set_ids][#{cc}]", options_from_collection_for_select(current_organisation.compliance_control_sets, :id, :name, w.compliance_control_set(cc).try(:id)), include_blank: true + + = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'workgroup_form' diff --git a/app/views/workgroups/edit.html.slim b/app/views/workgroups/edit.html.slim new file mode 100644 index 000000000..49847acf2 --- /dev/null +++ b/app/views/workgroups/edit.html.slim @@ -0,0 +1,8 @@ +- breadcrumb @workgroup +- page_header_content_for @workgroup + +.page_content + .container-fluid + .row + .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1 + == render 'form' diff --git a/app/workers/compliance_control_set_copy_worker.rb b/app/workers/compliance_control_set_copy_worker.rb index d18bb0c88..b87f5ad8e 100644 --- a/app/workers/compliance_control_set_copy_worker.rb +++ b/app/workers/compliance_control_set_copy_worker.rb @@ -1,8 +1,9 @@ class ComplianceControlSetCopyWorker include Sidekiq::Worker - def perform(control_set_id, referential_id) + def perform(control_set_id, referential_id, parent_type = nil, parent_id = nil) check_set = ComplianceControlSetCopier.new.copy(control_set_id, referential_id) + check_set.update parent_type: parent_type, parent_id: parent_id if parent_type && parent_id begin Net::HTTP.get(URI("#{Rails.configuration.iev_url}/boiv_iev/referentials/validator/new?id=#{check_set.id}")) diff --git a/app/workers/workbench_import_worker/object_state_updater.rb b/app/workers/workbench_import_worker/object_state_updater.rb index 1edc6b9a1..39d5f20b1 100644 --- a/app/workers/workbench_import_worker/object_state_updater.rb +++ b/app/workers/workbench_import_worker/object_state_updater.rb @@ -2,6 +2,11 @@ class WorkbenchImportWorker module ObjectStateUpdater + def resource entry + @_resources ||= {} + @_resources[entry.name] ||= workbench_import.resources.find_or_create_by(name: entry.name, resource_type: "referential") + end + def update_object_state entry, count workbench_import.update( total_steps: count ) update_spurious entry @@ -14,44 +19,48 @@ class WorkbenchImportWorker def update_foreign_lines entry return if entry.foreign_lines.empty? - workbench_import.messages.create( + resource(entry).messages.create( criticity: :error, message_key: 'foreign_lines_in_referential', message_attributes: { 'source_filename' => workbench_import.file.file.file, 'foreign_lines' => entry.foreign_lines.join(', ') }) + resource(entry).update status: :ERROR end def update_spurious entry return if entry.spurious.empty? - workbench_import.messages.create( + resource(entry).messages.create( criticity: :error, message_key: 'inconsistent_zip_file', message_attributes: { 'source_filename' => workbench_import.file.file.file, 'spurious_dirs' => entry.spurious.join(', ') }) + resource(entry).update status: :ERROR end def update_missing_calendar entry return unless entry.missing_calendar - workbench_import.messages.create( + resource(entry).messages.create( criticity: :error, message_key: 'missing_calendar_in_zip_file', message_attributes: { 'source_filename' => entry.name }) + resource(entry).update status: :ERROR end def update_wrong_calendar entry return unless entry.wrong_calendar - workbench_import.messages.create( + resource(entry).messages.create( criticity: :error, message_key: 'wrong_calendar_in_zip_file', message_attributes: { 'source_filename' => entry.name }) + resource(entry).update status: :ERROR end end end |
