scinote-web/app/services/storage_locations/import_service.rb

103 lines
3.3 KiB
Ruby
Raw Normal View History

2024-09-10 21:09:23 +08:00
# 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