class ArticlesController < ApplicationController before_action :authenticate_article_meta, :find_supplier def index sort = if params['sort'] case params['sort'] when 'name' then 'articles.name' when 'unit' then 'articles.unit' when 'article_category' then 'article_categories.name' when 'note' then 'articles.note' when 'availability' then 'articles.availability' when 'name_reverse' then 'articles.name DESC' when 'unit_reverse' then 'articles.unit DESC' when 'article_category_reverse' then 'article_categories.name DESC' when 'note_reverse' then 'articles.note DESC' when 'availability_reverse' then 'articles.availability DESC' end else 'article_categories.name, articles.name' end @articles = Article.undeleted.where(supplier_id: @supplier, type: nil).includes(:article_category).order(sort) if request.format.csv? send_data ArticlesCsv.new(@articles, encoding: 'utf-8').to_csv, filename: 'articles.csv', type: 'text/csv' return end @articles = @articles.where('articles.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil? @articles = @articles.page(params[:page]).per(@per_page) respond_to do |format| format.html format.js { render layout: false } end end def new @article = @supplier.articles.build(tax: FoodsoftConfig[:tax_default]) render layout: false end def copy @article = @supplier.articles.find(params[:article_id]).dup render layout: false end def edit @article = Article.find(params[:id]) render action: 'new', layout: false end def create @article = Article.new(params[:article]) if @article.valid? && @article.save render layout: false else render action: 'new', layout: false end end # Updates one Article and highlights the line if succeded def update @article = Article.find(params[:id]) if @article.update(params[:article]) render layout: false else render action: 'new', layout: false end end # Deletes article from database. send error msg, if article is used in a current order def destroy @article = Article.find(params[:id]) @article.mark_as_deleted unless @order = @article.in_open_order # If article is in an active Order, the Order will be returned render layout: false end # Renders a form for editing all articles from a supplier def edit_all @articles = @supplier.articles.undeleted end # Updates all article of specific supplier def update_all invalid_articles = false Article.transaction do if params[:articles].present? # Update other article attributes... @articles = Article.find(params[:articles].keys) @articles.each do |article| unless article.update(params[:articles][article.id.to_s]) invalid_articles ||= true # Remember that there are validation errors end end raise ActiveRecord::Rollback if invalid_articles # Rollback all changes end end if invalid_articles # An error has occurred, transaction has been rolled back. flash.now.alert = I18n.t('articles.controller.error_invalid') render :edit_all else # Successfully done. redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_all.notice') end end # makes different actions on selected articles def update_selected raise I18n.t('articles.controller.error_nosel') if params[:selected_articles].nil? articles = Article.find(params[:selected_articles]) Article.transaction do case params[:selected_action] when 'destroy' articles.each(&:mark_as_deleted) flash[:notice] = I18n.t('articles.controller.update_sel.notice_destroy') when 'setNotAvailable' articles.each { |a| a.update_attribute(:availability, false) } flash[:notice] = I18n.t('articles.controller.update_sel.notice_unavail') when 'setAvailable' articles.each { |a| a.update_attribute(:availability, true) } flash[:notice] = I18n.t('articles.controller.update_sel.notice_avail') else flash[:alert] = I18n.t('articles.controller.update_sel.notice_noaction') end end # action succeded redirect_to supplier_articles_url(@supplier, per_page: params[:per_page]) rescue StandardError => e redirect_to supplier_articles_url(@supplier, per_page: params[:per_page]), alert: I18n.t('errors.general_msg', msg: e) end # lets start with parsing articles from uploaded file, yeah # Renders the upload form def upload; end # Update articles from a spreadsheet def parse_upload uploaded_file = params[:articles]['file'] or raise I18n.t('articles.controller.parse_upload.no_file') options = { filename: uploaded_file.original_filename } options[:outlist_absent] = (params[:articles]['outlist_absent'] == '1') options[:convert_units] = (params[:articles]['convert_units'] == '1') @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_from_file uploaded_file.tempfile, options if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.parse_upload.notice') end @ignored_article_count = 0 rescue StandardError => e redirect_to upload_supplier_articles_path(@supplier), alert: I18n.t('errors.general_msg', msg: e.message) end # sync all articles with the external database # renders a form with articles, which should be updated def sync # check if there is an shared_supplier unless @supplier.shared_supplier redirect_to supplier_articles_url(@supplier), alert: I18n.t('articles.controller.sync.shared_alert', supplier: @supplier.name) end # sync articles against external database @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_all return unless @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.sync.notice') end # Updates, deletes articles when upload or sync form is submitted def update_synchronized @outlisted_articles = Article.find(params[:outlisted_articles].try(:keys) || []) @updated_articles = Article.find(params[:articles].try(:keys) || []) @updated_articles.map { |a| a.assign_attributes(params[:articles][a.id.to_s]) } @new_articles = (params[:new_articles] || []).map { |a| @supplier.articles.build(a) } has_error = false Article.transaction do # delete articles begin @outlisted_articles.each(&:mark_as_deleted) rescue StandardError # raises an exception when used in current order has_error = true end # Update articles @updated_articles.each { |a| a.save or has_error = true } # Add new articles @new_articles.each { |a| a.save or has_error = true } raise ActiveRecord::Rollback if has_error end if has_error @updated_article_pairs = @updated_articles.map do |article| orig_article = Article.find(article.id) [article, orig_article.unequal_attributes(article)] end flash.now.alert = I18n.t('articles.controller.error_invalid') render params[:from_action] == 'sync' ? :sync : :parse_upload else redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_sync.notice') end end # renders a view to import articles in local database # def shared # build array of keywords, required for ransack _all suffix q = params.fetch(:q, {}) q[:name_cont_all] = params.fetch(:name_cont_all_joined, '').split(' ') search = @supplier.shared_supplier.shared_articles.ransack(q) @articles = search.result.page(params[:page]).per(10) render layout: false end # fills a form whith values of the selected shared_article # when the direct parameter is set and the article is valid, it is imported directly def import @article = SharedArticle.find(params[:shared_article_id]).build_new_article(@supplier) @article.article_category_id = params[:article_category_id] if params[:article_category_id].present? if params[:direct] && params[:article_category_id].present? && @article.valid? && @article.save render action: 'create', layout: false else render action: 'new', layout: false end end private # @return [Number] Number of articles not taken into account when syncing (having no number) def ignored_article_count if action_name == 'sync' || params[:from_action] == 'sync' @ignored_article_count ||= @supplier.articles.undeleted.where(order_number: [nil, '']).count else 0 end end helper_method :ignored_article_count end