diff --git a/app/assets/javascripts/repositories/repository_datatable.js b/app/assets/javascripts/repositories/repository_datatable.js index 36827bcb6..64b5d3e4e 100644 --- a/app/assets/javascripts/repositories/repository_datatable.js +++ b/app/assets/javascripts/repositories/repository_datatable.js @@ -6,7 +6,6 @@ //= require repositories/row_editor.js - var RepositoryDatatable = (function(global) { 'use strict'; @@ -437,42 +436,51 @@ var RepositoryDatatable = (function(global) { }); } - function initExportActions() { - $(document).on('click', '#exportRepositoryRowsButton', function(e) { + function exportActionCallback(exportType, formId) { + const exportModal = $(`#export${exportType}Modal`); + $(document).on('click', `#export${exportType}Button`, function(e) { e.preventDefault(); e.stopPropagation(); - $('#exportRepositoryModal').modal('show'); + exportModal.modal('show'); }); - $('form#form-export').off().submit(function() { + $(`form#${formId}`).off().submit(function() { var form = this; if (currentMode === 'viewMode') { // Remove all hidden fields $(form).find('input[name=row_ids\\[\\]]').remove(); $(form).find('input[name=header_ids\\[\\]]').remove(); - // Append visible column information - $('table' + TABLE_ID + ' thead tr th').each(function() { - var th = $(this); - var val = prepareRepositoryHeaderForExport(th); + // Append visible column information for repository export + if (formId === 'form-repository-rows-export') { + $('table' + TABLE_ID + ' thead tr th').each(function() { + var th = $(this); + var val = prepareRepositoryHeaderForExport(th); - if (val) { - appendInput(form, val, 'header_ids[]'); - } - }); + if (val) { + appendInput(form, val, 'header_ids[]'); + } + }); + } // Append records - $.each(rowsSelected, function(index, rowId) { - appendInput(form, rowId, 'row_ids[]'); - }); + const exportRows = $('#exportStockConsumptionModal').attr('data-rows'); + + if (exportRows) { + appendInput(form, JSON.parse(exportRows)[0], 'row_ids[]'); + } else { + $.each(rowsSelected, function(index, rowId) { + appendInput(form, rowId, 'row_ids[]'); + }); + } } }) .on('ajax:beforeSend', function() { animateSpinner(null, true); }) .on('ajax:complete', function() { - $('#exportRepositoryModal').modal('hide'); + exportModal.modal('hide'); animateSpinner(null, false); }) .on('ajax:success', function(ev, data) { @@ -483,6 +491,14 @@ var RepositoryDatatable = (function(global) { }); } + function initExportActions() { + // Stock Consumption Export Action + exportActionCallback('StockConsumption', 'form-stock-consumption-export'); + + // RepositoryRow Export Action + exportActionCallback('RepositoryRows', 'form-repository-rows-export'); + } + // Adjust columns width in table header function adjustTableHeader() { TABLE.columns.adjust(); diff --git a/app/assets/javascripts/sitewide/repository_row_info_modal.js b/app/assets/javascripts/sitewide/repository_row_info_modal.js index 6dc86f22d..37f28ae54 100644 --- a/app/assets/javascripts/sitewide/repository_row_info_modal.js +++ b/app/assets/javascripts/sitewide/repository_row_info_modal.js @@ -38,7 +38,6 @@ }); $('#modal-info-repository-row #bar-code-image').attr('src', barCodeCanvas.toDataURL('image/png')); - $('#repository_row-info-table').DataTable({ dom: 'RBltpi', stateSave: false, @@ -59,6 +58,25 @@ animateSpinner(this); } }); + + // Stock Consumption Export Action + $(document).on('click', '.export-consumption-button', function(event) { + event.preventDefault(); + event.stopPropagation(); + $('#modal-info-repository-row').modal('hide'); + // set and unset data-rows value so export knows to ignore selected rows or not + $('#exportStockConsumptionModal') + .on('show.bs.modal', function() { + $('#exportStockConsumptionModal').attr( + 'data-rows', + $('#modal-info-repository-row .print-label-button').attr('data-rows') + ); + }) + .on('hide.bs.modal', function() { + $('#exportStockConsumptionModal').attr('data-rows', null); + }) + .modal('show'); + }); }); e.preventDefault(); return false; diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 15ed92752..e4d385d68 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -339,7 +339,7 @@ class RepositoriesController < ApplicationController if params[:row_ids] && params[:header_ids] RepositoryZipExport.generate_zip(params, @repository, current_user) log_activity(:export_inventory_items) - render json: { message: t('zip_export.export_request_success') }, status: :ok + render json: { message: t('zip_export.export_request_success') } else render json: { message: t('zip_export.export_error') }, status: :unprocessable_entity end @@ -356,6 +356,16 @@ class RepositoriesController < ApplicationController end end + def export_repository_stock_items + row_ids = @repository.repository_rows.where(id: params[:row_ids]).pluck(:id) + if row_ids.any? + RepositoryStockLedgerZipExport.generate_zip(row_ids, current_user.id) + render json: { message: t('zip_export.export_request_success') } + else + render json: { message: t('zip_export.export_error') }, status: :unprocessable_entity + end + end + def assigned_my_modules my_modules = MyModule.joins(:repository_rows).where(repository_rows: { repository: @repository }) .readable_by_user(current_user).distinct diff --git a/app/controllers/repository_rows_controller.rb b/app/controllers/repository_rows_controller.rb index 56647e0b4..9d94811d7 100644 --- a/app/controllers/repository_rows_controller.rb +++ b/app/controllers/repository_rows_controller.rb @@ -5,7 +5,7 @@ class RepositoryRowsController < ApplicationController include MyModulesHelper MAX_PRINTABLE_ITEM_NAME_LENGTH = 64 - before_action :load_repository, except: %i(show print rows_to_print print_zpl + before_action :load_repository, except: %i(print rows_to_print print_zpl validate_label_template_columns actions_toolbar) before_action :load_repository_row_print, only: %i(print rows_to_print print_zpl validate_label_template_columns) before_action :load_repository_or_snapshot, only: %i(print rows_to_print print_zpl validate_label_template_columns) diff --git a/app/models/repository_ledger_record.rb b/app/models/repository_ledger_record.rb index 1f4e4e03d..8cca5c2c8 100644 --- a/app/models/repository_ledger_record.rb +++ b/app/models/repository_ledger_record.rb @@ -3,7 +3,7 @@ class RepositoryLedgerRecord < ApplicationRecord auto_strip_attributes :comment - belongs_to :repository_stock_value, optional: true + belongs_to :repository_stock_value belongs_to :reference, polymorphic: true belongs_to :user end diff --git a/app/models/repository_stock_value.rb b/app/models/repository_stock_value.rb index 420373cc8..c0ba13806 100644 --- a/app/models/repository_stock_value.rb +++ b/app/models/repository_stock_value.rb @@ -10,6 +10,7 @@ class RepositoryStockValue < ApplicationRecord belongs_to :created_by, class_name: 'User', optional: true, inverse_of: :created_repository_stock_values belongs_to :last_modified_by, class_name: 'User', optional: true, inverse_of: :modified_repository_stock_values has_one :repository_cell, as: :value, dependent: :destroy, inverse_of: :value + has_one :repository_row, through: :repository_cell has_many :repository_ledger_records, dependent: :destroy accepts_nested_attributes_for :repository_cell diff --git a/app/services/repository_stock_ledger_zip_export.rb b/app/services/repository_stock_ledger_zip_export.rb new file mode 100644 index 000000000..b7ead95ff --- /dev/null +++ b/app/services/repository_stock_ledger_zip_export.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'csv' + +module RepositoryStockLedgerZipExport + COLUMNS = %w( + consumption_type + item_name + item_id + consumed_amount + consumed_amount_unit + added_amount + added_amount_unit + consumed_by + consumed_on + team + project + experiment + task + task_id + stock_amount_balance + stock_balance_unit + ).freeze + + def self.generate_zip(row_ids, user_id) + rows = generate_data(row_ids) + + zip = ZipExport.create(user_id: user_id) + zip.generate_exportable_zip( + user_id, + to_csv(rows), + :repositories + ) + end + + def self.to_csv(rows) + csv_header = COLUMNS.map { |col| I18n.t("repository_stock_values.stock_export.headers.#{col}") } + + CSV.generate do |csv| + csv << csv_header + rows.each do |row| + csv << row + end + end + end + + def self.generate_data(row_ids) + data = [] + repository_ledger_records = + RepositoryLedgerRecord.joins(repository_stock_value: :repository_row) + .includes(:user, { repository_stock_value: :repository_row }) + .where(repository_row: { id: row_ids }) + .joins('LEFT OUTER JOIN my_module_repository_rows ON + repository_ledger_records.reference_id = my_module_repository_rows.id') + .joins('LEFT OUTER JOIN my_modules ON + my_modules.id = my_module_repository_rows.my_module_id') + .joins('LEFT OUTER JOIN experiments ON experiments.id = my_modules.experiment_id') + .joins('LEFT OUTER JOIN projects ON projects.id = experiments.project_id') + .joins('LEFT OUTER JOIN teams ON teams.id = projects.team_id') + .order('repository_row.created_at, repository_ledger_records.created_at') + .select('repository_ledger_records.*, + my_modules.id AS module_id, my_modules.name AS module_name, + projects.name AS project_name, teams.name AS team_name, + experiments.name AS experiment_name') + # rubocop:disable Metrics/BlockLength + repository_ledger_records.each do |record| + consumption_type = record.reference_type == 'MyModuleRepositoryRow' ? 'Task' : 'Inventory' + + if record.amount.positive? + added_amount = record.amount.to_d + added_amount_unit = record.unit + else + consumed_amount = record.amount.abs.to_d + consumed_amount_unit = record.unit + end + + breadcrumbs_data = Array.new(4, '') + + row_data = [ + consumption_type, + record.repository_stock_value.repository_row.name, + record.repository_stock_value.repository_row.code, + consumed_amount, + consumed_amount_unit, + added_amount, + added_amount_unit, + record.user.full_name, + record.created_at.strftime(record.user.date_format), + record.team_name, + record.unit, + record.balance.to_d + ] + + if consumption_type == 'Task' + breadcrumbs_data = [ + record.project_name, + record.experiment_name, + record.module_name, + "#{MyModule::ID_PREFIX}#{record.module_id}" + ] + end + + row_data.insert(10, *breadcrumbs_data) + data << row_data + end + # rubocop:enable Metrics/BlockLength + data + end +end diff --git a/app/views/repositories/_export_repository_modal.html.erb b/app/views/repositories/_export_repository_rows_modal.html.erb similarity index 75% rename from app/views/repositories/_export_repository_modal.html.erb rename to app/views/repositories/_export_repository_rows_modal.html.erb index c00fe72de..33fa24f7d 100644 --- a/app/views/repositories/_export_repository_modal.html.erb +++ b/app/views/repositories/_export_repository_rows_modal.html.erb @@ -1,16 +1,16 @@
- +
@@ -113,7 +113,10 @@