mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-11-15 21:56:12 +08:00
103 lines
3.3 KiB
Ruby
103 lines
3.3 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'caxlsx'
|
||
|
|
||
|
module StorageLocations
|
||
|
class ImportService
|
||
|
def initialize(storage_location, file, user)
|
||
|
@storage_location = storage_location
|
||
|
@file = file
|
||
|
@user = user
|
||
|
end
|
||
|
|
||
|
def import_items
|
||
|
sheet = SpreadsheetParser.open_spreadsheet(@file)
|
||
|
incoming_items = SpreadsheetParser.spreadsheet_enumerator(sheet).reject { |r| r.all?(&:blank?) }
|
||
|
|
||
|
# Check if the file has proper headers
|
||
|
header = SpreadsheetParser.parse_row(incoming_items[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) }
|
||
|
|
||
|
# Check duplicate positions in the file
|
||
|
if @storage_location.with_grid? && incoming_items.pluck(0).uniq.length != incoming_items.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
|
||
|
|
||
|
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
|
||
|
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)
|
||
|
raise ActiveRecord::RecordNotFound
|
||
|
end
|
||
|
|
||
|
@storage_location.storage_location_repository_rows.create!(
|
||
|
repository_row: repository_row,
|
||
|
metadata: { position: position },
|
||
|
created_by: @user
|
||
|
)
|
||
|
end
|
||
|
rescue ActiveRecord::RecordNotFound
|
||
|
return { status: :error, message: error_message }
|
||
|
end
|
||
|
|
||
|
{ status: :ok }
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def convert_position_letter_to_number(position)
|
||
|
return unless position
|
||
|
|
||
|
column_letter = position[0]
|
||
|
row_number = position[1]
|
||
|
|
||
|
[column_letter.ord - 64, row_number]
|
||
|
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
|