Merge pull request #7850 from artoscinote/ma_SCI_11050

Refactor import and add activities [SCI-11050]
This commit is contained in:
Martin Artnik 2024-09-13 14:01:18 +02:00 committed by GitHub
commit 98415c0d8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 58 deletions

View file

@ -133,6 +133,16 @@ class StorageLocationsController < ApplicationController
def import_container
result = StorageLocations::ImportService.new(@storage_location, params[:file], current_user).import_items
if result[:status] == :ok
if (result[:assigned_count] + result[:unassigned_count] + result[:updated_count]).positive?
log_activity(
:storage_location_imported,
{
assigned_count: result[:assigned_count],
unassigned_count: result[:unassigned_count]
}
)
end
render json: result
else
render json: result, status: :unprocessable_entity

View file

@ -9,7 +9,7 @@ class StorageLocationRepositoryRow < ApplicationRecord
belongs_to :repository_row, inverse_of: :storage_location_repository_rows
belongs_to :created_by, class_name: 'User'
with_options if: -> { storage_location.container && storage_location.metadata['type'] == 'grid' } do
with_options if: -> { storage_location.container && storage_location.metadata['display_type'] == 'grid' } do
validate :position_must_be_present
validate :ensure_uniq_position
end

View file

@ -6,79 +6,94 @@ module StorageLocations
class ImportService
def initialize(storage_location, file, user)
@storage_location = storage_location
@file = file
@assigned_count = 0
@unassigned_count = 0
@updated_count = 0
@sheet = SpreadsheetParser.open_spreadsheet(file)
@user = user
end
def import_items
sheet = SpreadsheetParser.open_spreadsheet(@file)
incoming_items = SpreadsheetParser.spreadsheet_enumerator(sheet).reject { |r| r.all?(&:blank?) }
@rows = SpreadsheetParser.spreadsheet_enumerator(@sheet).reject { |r| r.all?(&:blank?) }
# Check if the file has proper headers
header = SpreadsheetParser.parse_row(incoming_items[0], sheet)
header = SpreadsheetParser.parse_row(@rows[0], @sheet)
return { status: :error, message: I18n.t('storage_locations.show.import_modal.errors.invalid_structure') } unless header[0] == 'Box position' && header[1] == 'Item ID'
# Remove first row
incoming_items.shift
incoming_items.map! { |r| SpreadsheetParser.parse_row(r, sheet) }
parse_rows!
# Check duplicate positions in the file
if @storage_location.with_grid? && incoming_items.pluck(0).uniq.length != incoming_items.length
if @storage_location.with_grid? && @rows.pluck(:position).uniq.length != @rows.length
return { status: :error, message: I18n.t('storage_locations.show.import_modal.errors.invalid_position') }
end
existing_items = @storage_location.storage_location_repository_rows.map do |item|
[convert_position_number_to_letter(item), item.repository_row_id, item.id]
end
items_to_unassign = []
existing_items.each do |existing_item|
if incoming_items.any? { |r| r[0] == existing_item[0] && r[1].to_i == existing_item[1] }
incoming_items.reject! { |r| r[0] == existing_item[0] && r[1].to_i == existing_item[1] }
else
items_to_unassign << existing_item[2]
end
end
error_message = ''
ActiveRecord::Base.transaction do
@storage_location.storage_location_repository_rows.where(id: items_to_unassign).discard_all
unassign_repository_rows!
incoming_items.each do |row|
if @storage_location.with_grid?
position = convert_position_letter_to_number(row[0])
unless position[0].to_i <= @storage_location.grid_size[0].to_i && position[1].to_i <= @storage_location.grid_size[1].to_i
error_message = I18n.t('storage_locations.show.import_modal.errors.invalid_position')
raise ActiveRecord::RecordInvalid
end
@rows.each do |row|
if @storage_location.with_grid? && !position_valid?(row[:position])
@error_message = I18n.t('storage_locations.show.import_modal.errors.invalid_position')
raise ActiveRecord::RecordInvalid
end
repository_row = RepositoryRow.find_by(id: row[1])
unless repository_row
error_message = I18n.t('storage_locations.show.import_modal.errors.invalid_item', row_id: row[1].to_i)
unless RepositoryRow.exists?(row[:repository_row_id])
@error_message = I18n.t('storage_locations.show.import_modal.errors.invalid_item', row_id: row[:repository_row_id])
raise ActiveRecord::RecordNotFound
end
@storage_location.storage_location_repository_rows.create!(
repository_row: repository_row,
metadata: { position: position },
created_by: @user
)
import_row!(row)
end
rescue ActiveRecord::RecordNotFound
return { status: :error, message: error_message }
end
{ status: :ok }
{ status: :ok, assigned_count: @assigned_count, unassigned_count: @unassigned_count, updated_count: @updated_count }
rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid
{ status: :error, message: @error_message }
end
private
def parse_rows!
# Remove first row
@rows.shift
@rows.map! do |r|
row = SpreadsheetParser.parse_row(r, @sheet)
{
position: convert_position_letter_to_number(row[0]),
repository_row_id: row[1].gsub('IT', '').to_i
}
end
end
def import_row!(row)
storage_location_repository_row =
@storage_location.storage_location_repository_rows
.find_or_initialize_by(
repository_row_id: row[:repository_row_id],
metadata: { position: row[:position] }
)
@assigned_count += 1 if storage_location_repository_row.new_record?
storage_location_repository_row.update!(
repository_row_id: row[:repository_row_id],
created_by: storage_location_repository_row.created_by || @user
)
end
def unassign_repository_rows!
@storage_location.storage_location_repository_rows.each do |s|
if @rows.exclude?({ position: s.metadata['position'], repository_row_id: s.repository_row_id })
@unassigned_count += 1
s.discard
end
end
end
def position_valid?(position)
position[0].to_i <= @storage_location.grid_size[0].to_i && position[1].to_i <= @storage_location.grid_size[1].to_i
end
def convert_position_letter_to_number(position)
return unless position
@ -87,16 +102,5 @@ module StorageLocations
[column_letter.ord - 64, row_number.to_i]
end
def convert_position_number_to_letter(item)
position = item.metadata['position']
return unless position
column_letter = ('A'..'Z').to_a[position[0] - 1]
row_number = position[1]
"#{column_letter}#{row_number}"
end
end
end