From 2c88843924c1b38eefd5b6fcc9c904a2018242b8 Mon Sep 17 00:00:00 2001 From: aignatov-bio <47317017+aignatov-bio@users.noreply.github.com> Date: Fri, 28 Jan 2022 11:10:56 +0100 Subject: [PATCH] Task stock consumption modal[SCI-6444][SCI-6445] (#3798) Add main logic for consumption on task [SCI-6444] Co-authored-by: Anton --- .../javascripts/my_modules/repositories.js | 7 ++ app/assets/javascripts/my_modules/stock.js | 68 +++++++++++++++++++ .../repositories/renderers/view_renderers.js | 8 +-- .../my_modules/stock_consumption_modal.scss | 16 +++++ .../stylesheets/repository/stock_modal.scss | 9 ++- .../my_module_repositories_controller.rb | 32 ++++++++- app/helpers/repository_datatable_helper.rb | 10 ++- app/models/my_module_repository_row.rb | 20 +++++- app/models/repository_row.rb | 3 +- app/views/my_modules/protocols.html.erb | 2 + .../_consume_stock_modal.html.erb | 39 +++++++++++ .../_consume_stock_modal_content.html.erb | 50 ++++++++++++++ .../simple_view_index.json.jbuilder | 2 +- config/initializers/assets.rb | 1 + config/locales/en.yml | 11 +++ config/routes.rb | 2 + 16 files changed, 267 insertions(+), 13 deletions(-) create mode 100644 app/assets/javascripts/my_modules/stock.js create mode 100644 app/assets/stylesheets/my_modules/stock_consumption_modal.scss create mode 100644 app/views/my_modules/repositories/_consume_stock_modal.html.erb create mode 100644 app/views/my_modules/repositories/_consume_stock_modal_content.html.erb diff --git a/app/assets/javascripts/my_modules/repositories.js b/app/assets/javascripts/my_modules/repositories.js index 4668666c1..32d9e05b6 100644 --- a/app/assets/javascripts/my_modules/repositories.js +++ b/app/assets/javascripts/my_modules/repositories.js @@ -191,6 +191,10 @@ var MyModuleRepositories = (function() { }); } + function reloadSimpleTable() { + SIMPLE_TABLE.ajax.reload(null, false); + } + function renderFullViewTable(tableContainer, options = {}) { if (FULL_VIEW_TABLE) FULL_VIEW_TABLE.destroy(); SELECTED_ROWS = {}; @@ -741,6 +745,9 @@ var MyModuleRepositories = (function() { initRepoistoryAssignView(); initSelectAllCheckbox(); initExportAssignedRows(); + }, + reloadSimpletable: () => { + reloadSimpleTable(); } }; }()); diff --git a/app/assets/javascripts/my_modules/stock.js b/app/assets/javascripts/my_modules/stock.js new file mode 100644 index 000000000..64f0c7a9e --- /dev/null +++ b/app/assets/javascripts/my_modules/stock.js @@ -0,0 +1,68 @@ +/* global SmartAnnotation I18n MyModuleRepositories */ +var MyModuleStockConsumption = (function() { + const CONSUMPTION_MODAL = '#consumeRepositoryStockValueModal'; + const WARNING_MODAL = '#consumeRepositoryStockValueModalWarning'; + + function initManageAction() { + $('.task-section').on('click', '.manage-repository-consumed-stock-value-link', function(e) { + e.preventDefault(); + $.ajax({ + url: $(this).attr('href'), + type: 'GET', + dataType: 'json', + success: (result) => { + var $manageModal = $(CONSUMPTION_MODAL); + $manageModal.find('.modal-content').html(result.html); + $manageModal.modal('show'); + SmartAnnotation.init($(CONSUMPTION_MODAL + ' #comment')[0]); + + $('#stock_consumption').on('change', function() { + let initialValue = parseFloat($(this).data('initial-value')); + let initialStock = parseFloat($(this).data('initial-stock')); + let finalValue = initialValue - ($(this).val() || 0) + initialStock; + $('.stock-final-container .value').text(finalValue); + $('.stock-final-container').toggleClass('error', finalValue <= 0); + $('.update-consumption-button').attr('disabled', $(this).val() === ''); + }); + + $(CONSUMPTION_MODAL + ' form').on('ajax:success', function() { + MyModuleRepositories.reloadSimpletable(); + $manageModal.modal('hide'); + $(WARNING_MODAL).modal('hide'); + }); + + $('.update-consumption-button').on('click', function(event, skipValidation) { + if (parseFloat($('.stock-final-container .value').text()) < 0 && !skipValidation) { + event.preventDefault(); + $manageModal.modal('hide'); + $(WARNING_MODAL).modal('show'); + let units = $(CONSUMPTION_MODAL).find('.consumption-container .units').text(); + let value = $('#stock_consumption').val(); + $(WARNING_MODAL).find('.modal-body p').text( + I18n.t('my_modules.repository.stock_warning_modal.description', { value: `${value} ${units}` }) + ); + } + }); + } + }); + }); + } + + function initWarningModal() { + $(WARNING_MODAL).on('click', '.cancel-consumption', function() { + $(WARNING_MODAL).modal('hide'); + $(CONSUMPTION_MODAL).modal('show'); + }).on('click', '.confirm-consumption-button', function() { + $('.update-consumption-button').trigger('click', [true]); + }); + } + + return { + init: () => { + initManageAction(); + initWarningModal(); + } + }; +}()); + +MyModuleStockConsumption.init(); diff --git a/app/assets/javascripts/repositories/renderers/view_renderers.js b/app/assets/javascripts/repositories/renderers/view_renderers.js index 4638fa1b6..f8a13cb04 100644 --- a/app/assets/javascripts/repositories/renderers/view_renderers.js +++ b/app/assets/javascripts/repositories/renderers/view_renderers.js @@ -210,16 +210,16 @@ $.fn.dataTable.render.RepositoryConsumedStockValue = function(data) { let canManage = $('.repository-table').data('stock-consumption-editable'); if (data && data.value.consumed_stock_formatted) { if (canManage) { - return ` - ${data.value.consumed_stock_formatted} + return ` + ${data.value.consumed_stock_formatted} ${data.value.unit} `; } return ` - ${data.value.consumed_stock_formatted} + ${data.value.consumed_stock_formatted} ${data.value.unit} `; } if (canManage && data && data.stock_present) { - return ` + return ` ${I18n.t('libraries.manange_modal_column.stock_type.add_stock_consumption')} `; diff --git a/app/assets/stylesheets/my_modules/stock_consumption_modal.scss b/app/assets/stylesheets/my_modules/stock_consumption_modal.scss new file mode 100644 index 000000000..39c94da5d --- /dev/null +++ b/app/assets/stylesheets/my_modules/stock_consumption_modal.scss @@ -0,0 +1,16 @@ + +#consumeRepositoryStockValueModal { + .consumption-container { + align-items: center; + display: grid; + grid-template-columns: 1fr 1fr; + + .units { + margin: 1.25em 0 0 .5em; + } + } + + .comments-container { + margin-bottom: 1em; + } +} diff --git a/app/assets/stylesheets/repository/stock_modal.scss b/app/assets/stylesheets/repository/stock_modal.scss index 85da0a14c..f14836569 100644 --- a/app/assets/stylesheets/repository/stock_modal.scss +++ b/app/assets/stylesheets/repository/stock_modal.scss @@ -1,7 +1,8 @@ // scss-lint:disable SelectorDepth // scss-lint:disable NestingDepth -.repository-stock-modal { +.repository-stock-modal, +#consumeRepositoryStockValueModal { .stock-update-view { align-items: center; display: grid; @@ -28,6 +29,12 @@ .units { @include font-small; } + + &.error { + .value { + color: $brand-danger; + } + } } .stock-arrow { diff --git a/app/controllers/my_module_repositories_controller.rb b/app/controllers/my_module_repositories_controller.rb index abd40cf73..c4d6214f3 100644 --- a/app/controllers/my_module_repositories_controller.rb +++ b/app/controllers/my_module_repositories_controller.rb @@ -5,8 +5,9 @@ class MyModuleRepositoriesController < ApplicationController before_action :load_my_module before_action :load_repository, except: %i(repositories_dropdown_list repositories_list_html) - before_action :check_my_module_view_permissions, except: :update + before_action :check_my_module_view_permissions, except: %i(update consume_modal update_consumption) before_action :check_repository_view_permissions, except: %i(repositories_dropdown_list repositories_list_html) + before_action :check_repository_row_consumption_permissions, only: %i(consume_modal update_consumption) before_action :check_assign_repository_records_permissions, only: :update def index_dt @@ -140,6 +141,31 @@ class MyModuleRepositoriesController < ApplicationController end end + def consume_modal + @repository_row = @repository.repository_rows.find(params[:row_id]) + @module_repository_row = @my_module.my_module_repository_rows.find_by(repository_row: @repository_row) + @stock_value = @module_repository_row.repository_row.repository_stock_value + render json: { + html: render_to_string( + partial: 'my_modules/repositories/consume_stock_modal_content.html.erb' + ) + } + end + + def update_consumption + module_repository_row = @my_module.my_module_repository_rows.find_by(id: params[:module_row_id]) + module_repository_row.with_lock do + module_repository_row.assign_attributes( + stock_consumption: params[:stock_consumption], + last_modified_by: current_user, + comment: params[:comment] + ) + module_repository_row.save! + end + + render json: {}, status: :ok + end + private def load_my_module @@ -164,6 +190,10 @@ class MyModuleRepositoriesController < ApplicationController render_403 unless can_assign_my_module_repository_rows?(@my_module) end + def check_repository_row_consumption_permissions + render_403 unless can_update_my_module_stock_consumption?(@my_module) + end + def update_flash_message(service) assigned_count = service.assigned_rows_count unassigned_count = service.unassigned_rows_count diff --git a/app/helpers/repository_datatable_helper.rb b/app/helpers/repository_datatable_helper.rb index ef80a1455..abb3ff87c 100644 --- a/app/helpers/repository_datatable_helper.rb +++ b/app/helpers/repository_datatable_helper.rb @@ -50,7 +50,7 @@ module RepositoryDatatableHelper end end - def prepare_simple_view_row_columns(repository_rows) + def prepare_simple_view_row_columns(repository_rows, my_module) repository_rows.map do |record| row = { DT_RowId: record.id, @@ -66,8 +66,14 @@ module RepositoryDatatableHelper end row['2'] = { stock_present: record.repository_stock_cell.present?, + updateStockConsumptionUrl: Rails.application.routes.url_helpers.consume_modal_my_module_repository_path( + my_module, + record.repository, + row_id: record.id + ), value: { - consumed_stock_formatted: record.consumed_stock + consumed_stock_formatted: record.consumed_stock, + unit: record.repository_stock_value.repository_stock_unit_item&.data } } end diff --git a/app/models/my_module_repository_row.rb b/app/models/my_module_repository_row.rb index acad0c607..6f46b6f7d 100644 --- a/app/models/my_module_repository_row.rb +++ b/app/models/my_module_repository_row.rb @@ -1,4 +1,7 @@ class MyModuleRepositoryRow < ApplicationRecord + attr_accessor :last_modified_by + attr_accessor :comment + belongs_to :assigned_by, foreign_key: 'assigned_by_id', class_name: 'User', @@ -13,17 +16,28 @@ class MyModuleRepositoryRow < ApplicationRecord around_save :deduct_stock_balance, if: :stock_consumption_changed? + before_save :nulify_stock_consumption, if: :stock_consumption_changed? + private + def nulify_stock_consumption + self.stock_consumption = nil if stock_consumption.zero? + end + def deduct_stock_balance stock_value = repository_row.repository_stock_value - delta = stock_consumption_was.to_d - stock_consumption.to_d - lock! + delta = stock_consumption.to_d - stock_consumption_was.to_d stock_value.lock! stock_value.amount = stock_value.amount - delta yield stock_value.save! - stock_value.repository_ledger_records.create!(user: last_modified_by, amount: delta, balance: stock_value.amount) + stock_value.repository_ledger_records.create!( + reference: self, + user: last_modified_by, + amount: delta, + balance: stock_value.amount, + comment: comment + ) save! end end diff --git a/app/models/repository_row.rb b/app/models/repository_row.rb index 43e16f9cd..977ec6441 100644 --- a/app/models/repository_row.rb +++ b/app/models/repository_row.rb @@ -34,7 +34,8 @@ class RepositoryRow < ApplicationRecord repository_date: 'RepositoryDateValue', repository_date_time_range: 'RepositoryDateTimeRangeValue', repository_time_range: 'RepositoryTimeRangeValue', - repository_date_range: 'RepositoryDateRangeValue' + repository_date_range: 'RepositoryDateRangeValue', + repository_stock: 'RepositoryStockValue' }.each do |relation, class_name| has_many "#{relation}_cells".to_sym, -> { where(value_type: class_name) }, class_name: 'RepositoryCell', inverse_of: :repository_row diff --git a/app/views/my_modules/protocols.html.erb b/app/views/my_modules/protocols.html.erb index 06740fb72..f5c44ab04 100644 --- a/app/views/my_modules/protocols.html.erb +++ b/app/views/my_modules/protocols.html.erb @@ -157,6 +157,8 @@ <%= render partial: 'assets/asset_delete_modal.html.erb' %> +<%= render partial: 'my_modules/repositories/consume_stock_modal.html.erb'%> + <%= stylesheet_link_tag 'datatables' %> <%= javascript_include_tag("my_modules/protocols") %> <%= javascript_include_tag("my_modules/status_flow") %> diff --git a/app/views/my_modules/repositories/_consume_stock_modal.html.erb b/app/views/my_modules/repositories/_consume_stock_modal.html.erb new file mode 100644 index 000000000..72c0cfdee --- /dev/null +++ b/app/views/my_modules/repositories/_consume_stock_modal.html.erb @@ -0,0 +1,39 @@ + + +