From 2b92fda9068dbac6cad75507ec3fafa1f8c94349 Mon Sep 17 00:00:00 2001 From: Gregor Lasnibat Date: Tue, 26 Mar 2024 11:08:17 +0100 Subject: [PATCH] (dev) POC for inventory import preview [SCI-10489] --- .../repository_checklist_items_value.rb | 6 -- app/models/repository_checklist_value.rb | 10 +- app/models/repository_date_time_value_base.rb | 11 ++- app/models/repository_date_value.rb | 11 ++- app/models/repository_list_value.rb | 4 +- app/models/repository_number_value.rb | 4 +- app/models/repository_status_value.rb | 4 +- app/models/repository_stock_value.rb | 4 +- app/models/repository_text_value.rb | 4 +- .../repository_base_value_serializer.rb | 4 +- .../repository_import_parser/importer.rb | 91 ++++++++++++++----- 11 files changed, 104 insertions(+), 49 deletions(-) diff --git a/app/models/repository_checklist_items_value.rb b/app/models/repository_checklist_items_value.rb index 07766f933..4ce8b0b58 100644 --- a/app/models/repository_checklist_items_value.rb +++ b/app/models/repository_checklist_items_value.rb @@ -5,10 +5,4 @@ class RepositoryChecklistItemsValue < ApplicationRecord belongs_to :repository_checklist_value, inverse_of: :repository_checklist_items_values validates :repository_checklist_item, :repository_checklist_value, presence: true - - after_destroy :destroy_empty_value - - def destroy_empty_value - repository_checklist_value.destroy! if repository_checklist_value.repository_checklist_items_values.blank? - end end diff --git a/app/models/repository_checklist_value.rb b/app/models/repository_checklist_value.rb index 302b03943..d9a37dfc5 100644 --- a/app/models/repository_checklist_value.rb +++ b/app/models/repository_checklist_value.rb @@ -70,17 +70,19 @@ class RepositoryChecklistValue < ApplicationRecord end end - def update_data!(new_data, user) + # TODO: after ticket for tracking changes on checklist items + def update_data!(new_data, user, preview: false) item_ids = new_data.is_a?(String) ? JSON.parse(new_data) : new_data + return destroy! if item_ids.blank? - # update!(repository_checklist_items: repository_cell.repository_column.repository_checklist_items.where(id: item_ids), last_modified_by: user) + self.last_modified_by = user self.repository_checklist_items = repository_cell.repository_column .repository_checklist_items .where(id: item_ids) - self.last_modified_by = user - save! + + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_date_time_value_base.rb b/app/models/repository_date_time_value_base.rb index 35f5e33b1..33628610f 100644 --- a/app/models/repository_date_time_value_base.rb +++ b/app/models/repository_date_time_value_base.rb @@ -19,10 +19,15 @@ class RepositoryDateTimeValueBase < ApplicationRecord I18n.l(data, format: format) end - def update_data!(new_data, user) - self.data = Time.zone.parse(new_data) + def update_data!(new_data, user, preview: false) + self.data = if new_data.is_a?(String) + Time.zone.parse(new_data) + else + new_data + end + self.last_modified_by = user - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_date_value.rb b/app/models/repository_date_value.rb index 216d0766c..2e5c21228 100644 --- a/app/models/repository_date_value.rb +++ b/app/models/repository_date_value.rb @@ -56,10 +56,15 @@ class RepositoryDateValue < RepositoryDateTimeValueBase value end - def update_data!(new_data, user) - self.data = Date.parse(new_data) + def update_data!(new_data, user, preview: false) + self.data = if new_data.is_a?(String) + Date.parse(new_data) + else + new_data.to_time.utc + end + self.last_modified_by = user - save! + preview ? validate : save! end def self.import_from_text(text, attributes, options = {}) diff --git a/app/models/repository_list_value.rb b/app/models/repository_list_value.rb index 81c2c97d5..5dda66721 100644 --- a/app/models/repository_list_value.rb +++ b/app/models/repository_list_value.rb @@ -57,10 +57,10 @@ class RepositoryListValue < ApplicationRecord new_data.to_i != repository_list_item_id end - def update_data!(new_data, user) + def update_data!(new_data, user, preview: false) self.repository_list_item_id = new_data.to_i self.last_modified_by = user - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_number_value.rb b/app/models/repository_number_value.rb index 58a437589..5e4706687 100644 --- a/app/models/repository_number_value.rb +++ b/app/models/repository_number_value.rb @@ -49,10 +49,10 @@ class RepositoryNumberValue < ApplicationRecord BigDecimal(new_data.to_s) != data end - def update_data!(new_data, user) + def update_data!(new_data, user, preview: false) self.data = BigDecimal(new_data.to_s) self.last_modified_by = user - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_status_value.rb b/app/models/repository_status_value.rb index 386426531..b3e64c2c4 100644 --- a/app/models/repository_status_value.rb +++ b/app/models/repository_status_value.rb @@ -48,10 +48,10 @@ class RepositoryStatusValue < ApplicationRecord new_data.to_i != repository_status_item_id end - def update_data!(new_data, user) + def update_data!(new_data, user, preview: false) self.repository_status_item_id = new_data.to_i self.last_modified_by = user - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_stock_value.rb b/app/models/repository_stock_value.rb index 2f882ce3e..c2170edd0 100644 --- a/app/models/repository_stock_value.rb +++ b/app/models/repository_stock_value.rb @@ -108,7 +108,7 @@ class RepositoryStockValue < ApplicationRecord (new_data[:unit_item_id].present? && new_data[:unit_item_id] != repository_stock_unit_item.id) end - def update_data!(new_data, user) + def update_data!(new_data, user, preview: false) self.low_stock_threshold = new_data[:low_stock_threshold].presence if new_data[:low_stock_threshold] self.repository_stock_unit_item = repository_cell .repository_column @@ -127,7 +127,7 @@ class RepositoryStockValue < ApplicationRecord unit: repository_stock_unit_item&.data ) self.amount = new_amount - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/models/repository_text_value.rb b/app/models/repository_text_value.rb index d6c8daa01..39348a5f1 100644 --- a/app/models/repository_text_value.rb +++ b/app/models/repository_text_value.rb @@ -36,10 +36,10 @@ class RepositoryTextValue < ApplicationRecord new_data != data end - def update_data!(new_data, user) + def update_data!(new_data, user, preview: false) self.data = new_data self.last_modified_by = user - save! + preview ? validate : save! end def snapshot!(cell_snapshot) diff --git a/app/serializers/repository_datatable/repository_base_value_serializer.rb b/app/serializers/repository_datatable/repository_base_value_serializer.rb index 8b20f6e42..ae8a4b9ee 100644 --- a/app/serializers/repository_datatable/repository_base_value_serializer.rb +++ b/app/serializers/repository_datatable/repository_base_value_serializer.rb @@ -2,7 +2,9 @@ module RepositoryDatatable class RepositoryBaseValueSerializer - attr_accessor :value_object, :value_type, :scope + attr_accessor :value_object, :value_type, :scope, :changes, :errors + + delegate :changes, :errors, to: :@value_object def initialize(value, scope:) @value_object = value diff --git a/app/utilities/repository_import_parser/importer.rb b/app/utilities/repository_import_parser/importer.rb index 05e2786d4..512a93940 100644 --- a/app/utilities/repository_import_parser/importer.rb +++ b/app/utilities/repository_import_parser/importer.rb @@ -29,7 +29,10 @@ module RepositoryImportParser fetch_columns return check_for_duplicate_columns if check_for_duplicate_columns - import_rows!(can_edit_existing_items, should_overwrite_with_empty_cells) + # Used for developing preview changes (will be removed) + preview = false + + import_rows!(can_edit_existing_items, should_overwrite_with_empty_cells, preview: preview) end private @@ -55,7 +58,7 @@ module RepositoryImportParser end end - def import_rows!(can_edit_existing_items, should_overwrite_with_empty_cells) + def import_rows!(can_edit_existing_items, should_overwrite_with_empty_cells, preview: false) errors = false duplicate_ids = SpreadsheetParser.duplicate_ids(@sheet) @@ -68,7 +71,7 @@ module RepositoryImportParser next if row.blank? # Skip duplicates - next if duplicate_ids.include?(row.first) + next if duplicate_ids.include?(row.first) && !preview unless @header_skipped @header_skipped = true @@ -87,7 +90,7 @@ module RepositoryImportParser if index == @name_index # check if row (inventory) already exists - existing_row = RepositoryRow.find_by(id: incoming_row[0]) + existing_row = RepositoryRow.find_by(id: incoming_row[0].gsub(RepositoryRow::ID_PREFIX, '')) # if it doesn't exist create it unless existing_row @@ -104,16 +107,23 @@ module RepositoryImportParser next end - # if it does exist but shouldn't be edited, error out and break - if existing_row && can_edit_existing_items == '0' - errors = true - break - end - - # if it does exist and should be edited, update the existing row - if existing_row && can_edit_existing_items == '1' - # update the existing row with incoming row data + # if it's a preview always add the existing row + if preview new_full_row[:repository_row] = existing_row + + # otherwise add according to criteria + else + # if it does exist but shouldn't be edited, error out and break + if existing_row && can_edit_existing_items == '0' + errors = true + break + end + + # if it does exist and should be edited, update the existing row + if existing_row && can_edit_existing_items == '1' + # update the existing row with incoming row data + new_full_row[:repository_row] = existing_row + end end end @@ -128,13 +138,15 @@ module RepositoryImportParser next if batch_counter < IMPORT_BATCH_SIZE - import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells) + import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells, preview: preview) full_row_import_batch = [] batch_counter = 0 end # Import of the remaining rows - import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells) if full_row_import_batch.any? + import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells, preview: preview) if full_row_import_batch.any? + + full_row_import_batch end if errors @@ -145,7 +157,7 @@ module RepositoryImportParser { status: :ok, nr_of_added: @new_rows_added, total_nr: @total_new_rows } end - def import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells) + def import_batch_to_database(full_row_import_batch, can_edit_existing_items, should_overwrite_with_empty_cells, preview: false) skipped_rows = [] full_row_import_batch.each do |full_row| @@ -183,18 +195,30 @@ module RepositoryImportParser next if cell_value.nil? && existing_cell.nil? - # no existing_cell. Create a new one. - if !existing_cell - cell_value.repository_cell.value = cell_value - cell_value.save!(validate: false) - else + if existing_cell # existing_cell present && !can_edit_existing_items next if can_edit_existing_items == '0' # existing_cell present && can_edit_existing_items if can_edit_existing_items == '1' # if incoming cell is not empty - existing_cell.value.update_data!(cell_value.data, @user) if !cell_value.nil? + case cell_value + + when RepositoryStockValue + existing_cell.value.update_data!(cell_value, @user, preview: preview) unless cell_value.nil? + + when RepositoryListValue + repository_list_item_id = cell_value[:repository_list_item_id] + existing_cell.value.update_data!(repository_list_item_id, @user, preview: preview) unless cell_value.nil? + + when RepositoryStatusValue + repository_status_item_id = cell_value[:repository_status_item_id] + existing_cell.value.update_data!(repository_status_item_id, @user, preview: preview) unless cell_value.nil? + + else + sanitized_cell_value_data = sanitize_cell_value_data(cell_value.data) + existing_cell.value.update_data!(sanitized_cell_value_data, @user, preview: preview) unless cell_value.nil? + end # if incoming cell is empty && should_overwrite_with_empty_cells existing_cell.value.destroy! if cell_value.nil? && should_overwrite_with_empty_cells == '1' @@ -202,11 +226,34 @@ module RepositoryImportParser # if incoming cell is empty && !should_overwrite_with_empty_cells next if cell_value.nil? && should_overwrite_with_empty_cells == '0' end + else + # no existing_cell. Create a new one. + cell_value.repository_cell.value = cell_value + cell_value.save!(validate: false) end end end end + def sanitize_cell_value_data(cell_value_data) + case cell_value_data + # when importing from .csv for: + # repository_text_value, repository_number_value, repository_date_value, repository_date_time_value_base + when String, Numeric, Date, Time + cell_value_data + when Array + cell_value_data.filter_map do |element| + if element.is_a?(Hash) && element.key?(:value) + element[:value].to_s + elsif element.is_a?(String) + element + end + end + else + [] + end + end + def try_decimal_to_string(value) if value.is_a?(BigDecimal) value.frac.zero? ? value.to_i.to_s : value.to_s