x_11_file_import_via_plugin #65

Open
flip wants to merge 65 commits from x_11_file_import_via_plugin into develop
331 changed files with 4263 additions and 4507 deletions
Showing only changes of commit fb2b4d8a8a - Show all commits

File diff suppressed because it is too large Load diff

93
Gemfile
View file

@ -1,75 +1,74 @@
# A sample Gemfile
source "https://rubygems.org"
source 'https://rubygems.org'
gem "rails", '~> 7.0'
gem 'mail', '~> 2.7.1' # bug with mail 2.8.0 https://github.com/mikel/mail/issues/1489
gem 'rails', '~> 7.0'
gem 'sassc-rails'
gem 'less-rails'
gem 'sassc-rails'
gem 'uglifier'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby
gem 'jquery-rails'
gem 'select2-rails'
gem 'rails_tokeninput'
gem 'bootsnap', require: false
gem 'bootstrap-datepicker-rails'
gem 'date_time_attribute'
gem 'rails-assets-listjs', '0.2.0.beta.4' # remember to maintain list.*.js plugins and template engines on update
gem 'i18n-js', '~> 3.0.0.rc8'
gem 'jquery-rails'
gem 'rails-assets-listjs', '0.2.0.beta.4' # remember to maintain list.*.js plugins and template engines on update
gem 'rails-i18n'
gem 'bootsnap', require: false
gem 'rails_tokeninput'
gem 'select2-rails'
gem 'mysql2'
gem 'prawn'
gem 'prawn-table'
gem 'haml'
gem 'haml-rails'
gem 'kaminari'
gem 'simple_form'
gem 'inherited_resources'
gem 'active_model_serializers', '~> 0.10.0'
gem 'acts_as_tree'
gem 'attribute_normalizer'
gem 'daemons'
gem 'doorkeeper'
gem 'doorkeeper-i18n'
gem 'haml'
gem 'haml-rails'
gem 'ice_cube'
gem 'inherited_resources'
gem 'kaminari'
gem 'mysql2'
gem 'prawn'
gem 'prawn-table'
gem 'puma'
gem 'rack-cors', require: 'rack/cors'
gem 'active_model_serializers', '~> 0.10.0'
gem 'twitter-bootstrap-rails', '~> 2.2.8'
gem 'rails-settings-cached', '= 0.4.3' # caching breaks tests until Rails 5 https://github.com/huacnlee/rails-settings-cached/issues/73
gem 'ransack'
gem 'resque'
gem 'ruby-units'
gem 'sd_notify'
gem 'simple_form'
gem 'simple-navigation', '~> 3.14.0' # 3.x for simple_navigation_bootstrap
gem 'simple-navigation-bootstrap'
gem 'sprockets', '< 4'
gem 'ransack'
gem 'acts_as_tree'
gem 'rails-settings-cached', '= 0.4.3' # caching breaks tests until Rails 5 https://github.com/huacnlee/rails-settings-cached/issues/73
gem 'resque'
gem 'puma'
gem 'sd_notify'
gem 'twitter-bootstrap-rails', '~> 2.2.8'
gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb
gem 'ruby-units'
gem 'attribute_normalizer'
gem 'ice_cube'
# At time of development 01-06-2022 mmddyyyy necessary fix for config_helper.rb form builder was not in rubygems so we pull from github, see: https://github.com/gregschmit/recurring_select/pull/152
gem 'exception_notification'
gem 'gaffe'
gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114
gem 'midi-smtp-server'
gem 'mime-types'
gem 'recurring_select', git: 'https://github.com/gregschmit/recurring_select'
gem 'roo'
gem 'roo-xls'
gem 'spreadsheet'
gem 'exception_notification'
gem 'gaffe'
gem 'ruby-filemagic'
gem 'mime-types'
gem 'midi-smtp-server'
gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114
gem 'rswag-api'
gem 'rswag-ui'
gem 'ruby-filemagic'
gem 'spreadsheet'
# we use the git version of acts_as_versioned, and need to include it in this Gemfile
gem 'acts_as_versioned', git: 'https://github.com/technoweenie/acts_as_versioned.git'
gem 'foodsoft_wiki', path: 'plugins/wiki'
gem 'foodsoft_messages', path: 'plugins/messages'
gem 'foodsoft_documents', path: 'plugins/documents'
gem 'foodsoft_discourse', path: 'plugins/discourse'
gem 'foodsoft_documents', path: 'plugins/documents'
gem 'foodsoft_links', path: 'plugins/links'
gem 'foodsoft_messages', path: 'plugins/messages'
gem 'foodsoft_polls', path: 'plugins/polls'
gem 'foodsoft_wiki', path: 'plugins/wiki'
# plugins not enabled by default
# gem 'foodsoft_current_orders', path: 'plugins/current_orders'
@ -77,10 +76,10 @@ gem 'foodsoft_polls', path: 'plugins/polls'
# gem 'foodsoft_uservoice', path: 'plugins/uservoice'
group :development do
gem 'sqlite3', '~> 1.3.6'
gem 'mailcatcher'
gem 'web-console'
gem 'listen'
gem 'mailcatcher'
gem 'sqlite3', '~> 1.3.6'
gem 'web-console'
# Better error output
gem 'better_errors'
@ -108,17 +107,17 @@ group :development, :test do
end
group :test do
gem 'rspec-rails'
gem 'apparition' # Capybara javascript driver
gem 'capybara'
gem 'connection_pool'
gem 'database_cleaner'
gem 'factory_bot_rails'
gem 'faker'
gem 'capybara'
gem 'apparition' # Capybara javascript driver
gem 'database_cleaner'
gem 'connection_pool'
gem 'rspec-rails'
# need to include rspec components before i18n-spec or rake fails in test environment
gem 'i18n-spec'
gem 'rspec-core'
gem 'rspec-rerun'
gem 'i18n-spec'
# code coverage
gem 'simplecov', require: false
gem 'simplecov-lcov', require: false

View file

@ -1,7 +1,7 @@
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
require File.expand_path('../config/application', __FILE__)
require File.expand_path('config/application', __dir__)
require 'rake'
require 'rspec-rerun/tasks' if defined?(RSpec) # http://stackoverflow.com/a/16853615/2866660

View file

@ -3,39 +3,39 @@ class Admin::BankAccountsController < Admin::BaseController
def new
@bank_account = BankAccount.new(params[:bank_account])
render :layout => false
render layout: false
end
def edit
@bank_account = BankAccount.find(params[:id])
render action: 'new', layout: false
end
def create
@bank_account = BankAccount.new(params[:bank_account])
if @bank_account.valid? && @bank_account.save
redirect_to update_bank_accounts_admin_finances_url, :status => 303
redirect_to update_bank_accounts_admin_finances_url, status: :see_other
else
render :action => 'new', :layout => false
render action: 'new', layout: false
end
end
def edit
@bank_account = BankAccount.find(params[:id])
render :action => 'new', :layout => false
end
def update
@bank_account = BankAccount.find(params[:id])
if @bank_account.update(params[:bank_account])
redirect_to update_bank_accounts_admin_finances_url, :status => 303
redirect_to update_bank_accounts_admin_finances_url, status: :see_other
else
render :action => 'new', :layout => false
render action: 'new', layout: false
end
end
def destroy
@bank_account = BankAccount.find(params[:id])
@bank_account.destroy
redirect_to update_bank_accounts_admin_finances_url, :status => 303
rescue => error
flash.now[:alert] = error.message
redirect_to update_bank_accounts_admin_finances_url, status: :see_other
rescue StandardError => e
flash.now[:alert] = e.message
render template: 'shared/alert'
end
end

View file

@ -6,6 +6,11 @@ class Admin::BankGatewaysController < Admin::BaseController
render layout: false
end
def edit
@bank_gateway = BankGateway.find(params[:id])
render action: 'new', layout: false
end
def create
@bank_gateway = BankGateway.new(params[:bank_gateway])
if @bank_gateway.valid? && @bank_gateway.save
@ -15,11 +20,6 @@ class Admin::BankGatewaysController < Admin::BaseController
end
end
def edit
@bank_gateway = BankGateway.find(params[:id])
render action: 'new', layout: false
end
def update
@bank_gateway = BankGateway.find(params[:id])

View file

@ -1,5 +1,5 @@
class Admin::ConfigsController < Admin::BaseController
before_action :get_tabs, only: [:show, :list]
before_action :get_tabs, only: %i[show list]
def show
@current_tab = @tabs.include?(params[:tab]) ? params[:tab] : @tabs.first
@ -16,7 +16,7 @@ class Admin::ConfigsController < Admin::BaseController
def update
parse_recurring_selects! params[:config][:order_schedule]
ActiveRecord::Base.transaction do
# TODO support nested configuration keys
# TODO: support nested configuration keys
params[:config].each do |key, val|
FoodsoftConfig[key] = convert_config_value val
end
@ -29,7 +29,7 @@ class Admin::ConfigsController < Admin::BaseController
# Set configuration tab names as `@tabs`
def get_tabs
@tabs = %w(foodcoop payment tasks messages layout language security others)
@tabs = %w[foodcoop payment tasks messages layout language security others]
# allow engines to modify this list
engines = Rails::Engine.subclasses.map(&:instance).select { |e| e.respond_to?(:configuration) }
engines.each { |e| e.configuration(@tabs, self) }
@ -38,8 +38,9 @@ class Admin::ConfigsController < Admin::BaseController
# turn recurring rules into something palatable
def parse_recurring_selects!(config)
if config
for k in [:pickup, :boxfill, :ends] do
return unless config
for k in %i[pickup boxfill ends] do
if config[k]
# allow clearing it using dummy value '{}' ('' would break recurring_select)
if config[k][:recurr].present? && config[k][:recurr] != '{}'
@ -51,7 +52,6 @@ class Admin::ConfigsController < Admin::BaseController
end
end
end
end
def convert_config_value(value)
if value.is_a? ActionController::Parameters

View file

@ -10,21 +10,21 @@ class Admin::FinancesController < Admin::BaseController
def update_bank_accounts
@bank_accounts = BankAccount.order('name')
render :layout => false
render layout: false
end
def update_bank_gateways
@bank_gateways = BankGateway.order('name')
render :layout => false
render layout: false
end
def update_transaction_types
@financial_transaction_classes = FinancialTransactionClass.includes(:financial_transaction_types).order('name ASC')
render :layout => false
render layout: false
end
def update_supplier_categories
@supplier_categories = SupplierCategory.order('name')
render :layout => false
render layout: false
end
end

View file

@ -6,25 +6,25 @@ class Admin::FinancialTransactionClassesController < Admin::BaseController
render layout: false
end
def create
@financial_transaction_class = FinancialTransactionClass.new(params[:financial_transaction_class])
if @financial_transaction_class.save
redirect_to update_transaction_types_admin_finances_url, status: 303
else
render action: 'new', layout: false
end
end
def edit
@financial_transaction_class = FinancialTransactionClass.find(params[:id])
render action: 'new', layout: false
end
def create
@financial_transaction_class = FinancialTransactionClass.new(params[:financial_transaction_class])
if @financial_transaction_class.save
redirect_to update_transaction_types_admin_finances_url, status: :see_other
else
render action: 'new', layout: false
end
end
def update
@financial_transaction_class = FinancialTransactionClass.find(params[:id])
if @financial_transaction_class.update(params[:financial_transaction_class])
redirect_to update_transaction_types_admin_finances_url, status: 303
redirect_to update_transaction_types_admin_finances_url, status: :see_other
else
render action: 'new', layout: false
end
@ -33,9 +33,9 @@ class Admin::FinancialTransactionClassesController < Admin::BaseController
def destroy
@financial_transaction_class = FinancialTransactionClass.find(params[:id])
@financial_transaction_class.destroy!
redirect_to update_transaction_types_admin_finances_url, status: 303
rescue => error
flash.now[:alert] = error.message
redirect_to update_transaction_types_admin_finances_url, status: :see_other
rescue StandardError => e
flash.now[:alert] = e.message
render template: 'shared/alert'
end
end

View file

@ -7,25 +7,25 @@ class Admin::FinancialTransactionTypesController < Admin::BaseController
render layout: false
end
def create
@financial_transaction_type = FinancialTransactionType.new(params[:financial_transaction_type])
if @financial_transaction_type.save
redirect_to update_transaction_types_admin_finances_url, status: 303
else
render action: 'new', layout: false
end
end
def edit
@financial_transaction_type = FinancialTransactionType.find(params[:id])
render action: 'new', layout: false
end
def create
@financial_transaction_type = FinancialTransactionType.new(params[:financial_transaction_type])
if @financial_transaction_type.save
redirect_to update_transaction_types_admin_finances_url, status: :see_other
else
render action: 'new', layout: false
end
end
def update
@financial_transaction_type = FinancialTransactionType.find(params[:id])
if @financial_transaction_type.update(params[:financial_transaction_type])
redirect_to update_transaction_types_admin_finances_url, status: 303
redirect_to update_transaction_types_admin_finances_url, status: :see_other
else
render action: 'new', layout: false
end
@ -34,9 +34,9 @@ class Admin::FinancialTransactionTypesController < Admin::BaseController
def destroy
@financial_transaction_type = FinancialTransactionType.find(params[:id])
@financial_transaction_type.destroy!
redirect_to update_transaction_types_admin_finances_url, status: 303
rescue => error
flash.now[:alert] = error.message
redirect_to update_transaction_types_admin_finances_url, status: :see_other
rescue StandardError => e
flash.now[:alert] = e.message
render template: 'shared/alert'
end
end

View file

@ -3,28 +3,28 @@ class Admin::MailDeliveryStatusController < Admin::BaseController
def index
@maildeliverystatus = MailDeliveryStatus.order(created_at: :desc)
@maildeliverystatus = @maildeliverystatus.where(email: params[:email]) unless params[:email].blank?
@maildeliverystatus = @maildeliverystatus.where(email: params[:email]) if params[:email].present?
@maildeliverystatus = @maildeliverystatus.page(params[:page]).per(@per_page)
end
def show
@maildeliverystatus = MailDeliveryStatus.find(params[:id])
filename = "maildeliverystatus_#{params[:id]}.#{MIME::Types[@maildeliverystatus.attachment_mime].first.preferred_extension}"
send_data(@maildeliverystatus.attachment_data, :filename => filename, :type => @maildeliverystatus.attachment_mime)
send_data(@maildeliverystatus.attachment_data, filename: filename, type: @maildeliverystatus.attachment_mime)
end
def destroy_all
@maildeliverystatus = MailDeliveryStatus.delete_all
redirect_to admin_mail_delivery_status_index_path, notice: t('.notice')
rescue => error
redirect_to admin_mail_delivery_status_index_path, alert: I18n.t('errors.general_msg', msg: error.message)
rescue StandardError => e
redirect_to admin_mail_delivery_status_index_path, alert: I18n.t('errors.general_msg', msg: e.message)
end
def destroy
@maildeliverystatus = MailDeliveryStatus.find(params[:id])
@maildeliverystatus.destroy
redirect_to admin_mail_delivery_status_index_path, notice: t('.notice')
rescue => error
redirect_to admin_mail_delivery_status_index_path, alert: I18n.t('errors.general_msg', msg: error.message)
rescue StandardError => e
redirect_to admin_mail_delivery_status_index_path, alert: I18n.t('errors.general_msg', msg: e.message)
end
end

View file

@ -2,16 +2,15 @@ class Admin::OrdergroupsController < Admin::BaseController
inherit_resources
def index
@ordergroups = Ordergroup.undeleted.sort_by_param(params["sort"])
@ordergroups = Ordergroup.undeleted.sort_by_param(params['sort'])
if request.format.csv?
send_data OrdergroupsCsv.new(@ordergroups).to_csv, filename: 'ordergroups.csv', type: 'text/csv'
send_data OrdergroupsCsv.new(@ordergroups).to_csv, filename: 'ordergroups.csv',
type: 'text/csv'
end
# if somebody uses the search field:
unless params[:query].blank?
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%")
end
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:query]}%") if params[:query].present?
@ordergroups = @ordergroups.page(params[:page]).per(@per_page)
end
@ -19,8 +18,8 @@ class Admin::OrdergroupsController < Admin::BaseController
def destroy
@ordergroup = Ordergroup.find(params[:id])
@ordergroup.mark_as_deleted
redirect_to admin_ordergroups_url, notice: t('admin.ordergroups.destroy.notice')
rescue => error
redirect_to admin_ordergroups_url, alert: t('admin.ordergroups.destroy.error')
redirect_to admin_ordergroups_url, notice: t('.notice')
rescue StandardError => e
redirect_to admin_ordergroups_url, alert: t('.error')
end
end

View file

@ -6,6 +6,11 @@ class Admin::SupplierCategoriesController < Admin::BaseController
render layout: false
end
def edit
@supplier_category = SupplierCategory.find(params[:id])
render action: 'new', layout: false
end
def create
@supplier_category = SupplierCategory.new(params[:supplier_category])
if @supplier_category.valid? && @supplier_category.save
@ -15,11 +20,6 @@ class Admin::SupplierCategoriesController < Admin::BaseController
end
end
def edit
@supplier_category = SupplierCategory.find(params[:id])
render action: 'new', layout: false
end
def update
@supplier_category = SupplierCategory.find(params[:id])

View file

@ -3,16 +3,14 @@ class Admin::UsersController < Admin::BaseController
def index
@users = params[:show_deleted] ? User.deleted : User.undeleted
@users = @users.sort_by_param(params["sort"])
@users = @users.sort_by_param(params['sort'])
@users = @users.includes(:mail_delivery_status)
if request.format.csv?
send_data UsersCsv.new(@users).to_csv, filename: 'users.csv', type: 'text/csv'
end
send_data UsersCsv.new(@users).to_csv, filename: 'users.csv', type: 'text/csv' if request.format.csv?
# if somebody uses the search field:
@users = @users.natural_search(params[:user_name]) unless params[:user_name].blank?
@users = @users.natural_search(params[:user_name]) if params[:user_name].present?
@users = @users.page(params[:page]).per(@per_page)
end
@ -20,17 +18,17 @@ class Admin::UsersController < Admin::BaseController
def destroy
@user = User.find(params[:id])
@user.mark_as_deleted
redirect_to admin_users_url, notice: t('admin.users.destroy.notice')
rescue => error
redirect_to admin_users_url, alert: t('admin.users.destroy.error', error: error.message)
redirect_to admin_users_url, notice: t('.notice')
rescue StandardError => e
redirect_to admin_users_url, alert: t('.error', error: e.message)
end
def restore
@user = User.find(params[:id])
@user.restore
redirect_to admin_users_url, notice: t('admin.users.restore.notice')
rescue => error
redirect_to admin_users_url, alert: t('admin.users.restore.error', error: error.message)
redirect_to admin_users_url, notice: t('.notice')
rescue StandardError => e
redirect_to admin_users_url, alert: t('.error', error: e.message)
end
def sudo

View file

@ -4,7 +4,7 @@ class Admin::WorkgroupsController < Admin::BaseController
def index
@workgroups = Workgroup.order('name ASC')
# if somebody uses the search field:
@workgroups = @workgroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].blank?
@workgroups = @workgroups.where('name LIKE ?', "%#{params[:query]}%") if params[:query].present?
@workgroups = @workgroups.page(params[:page]).per(@per_page)
end
@ -12,8 +12,8 @@ class Admin::WorkgroupsController < Admin::BaseController
def destroy
@workgroup = Workgroup.find(params[:id])
@workgroup.destroy
redirect_to admin_workgroups_url, notice: t('admin.workgroups.destroy.notice')
rescue => error
redirect_to admin_workgroups_url, alert: t('admin.workgroups.destroy.error', error: error.message)
redirect_to admin_workgroups_url, notice: t('.notice')
rescue StandardError => e
redirect_to admin_workgroups_url, alert: t('.error', error: e.message)
end
end

View file

@ -20,29 +20,30 @@ class Api::V1::BaseController < ApplicationController
def require_ordergroup
authenticate
unless current_ordergroup.present?
raise Api::Errors::PermissionRequired.new('Forbidden, must be in an ordergroup')
end
return if current_ordergroup.present?
raise Api::Errors::PermissionRequired, 'Forbidden, must be in an ordergroup'
end
def require_minimum_balance
minimum_balance = FoodsoftConfig[:minimum_balance] or return
if current_ordergroup.account_balance < minimum_balance
raise Api::Errors::PermissionRequired.new(t('application.controller.error_minimum_balance', min: minimum_balance))
end
return unless current_ordergroup.account_balance < minimum_balance
raise Api::Errors::PermissionRequired, t('application.controller.error_minimum_balance', min: minimum_balance)
end
def require_enough_apples
if current_ordergroup.not_enough_apples?
s = t('group_orders.messages.not_enough_apples', apples: current_ordergroup.apples, stop_ordering_under: FoodsoftConfig[:stop_ordering_under])
raise Api::Errors::PermissionRequired.new(s)
end
return unless current_ordergroup.not_enough_apples?
s = t('group_orders.messages.not_enough_apples', apples: current_ordergroup.apples,
stop_ordering_under: FoodsoftConfig[:stop_ordering_under])
raise Api::Errors::PermissionRequired, s
end
def require_config_enabled(config)
unless FoodsoftConfig[config]
raise Api::Errors::PermissionRequired.new(t('application.controller.error_not_enabled', config: config))
end
return if FoodsoftConfig[config]
raise Api::Errors::PermissionRequired, t('application.controller.error_not_enabled', config: config)
end
def skip_session
@ -52,12 +53,12 @@ class Api::V1::BaseController < ApplicationController
def not_found_handler(e)
# remove where-clauses from error message (not suitable for end-users)
msg = e.message.try { |m| m.sub(/\s*\[.*?\]\s*$/, '') } || 'Not found'
render status: 404, json: { error: 'not_found', error_description: msg }
render status: :not_found, json: { error: 'not_found', error_description: msg }
end
def not_acceptable_handler(e)
msg = e.message || 'Data not acceptable'
render status: 422, json: { error: 'not_acceptable', error_description: msg }
render status: :unprocessable_entity, json: { error: 'not_acceptable', error_description: msg }
end
def doorkeeper_unauthorized_render_options(error:)
@ -70,11 +71,11 @@ class Api::V1::BaseController < ApplicationController
def permission_required_handler(e)
msg = e.message || 'Forbidden, user has no access'
render status: 403, json: { error: 'forbidden', error_description: msg }
render status: :forbidden, json: { error: 'forbidden', error_description: msg }
end
# @todo something with ApplicationHelper#show_user
def show_user(user = current_user, **options)
def show_user(user = current_user, **_options)
user.display
end
end

View file

@ -16,7 +16,8 @@ class Api::V1::User::FinancialTransactionsController < Api::V1::BaseController
def create
transaction_type = FinancialTransactionType.find(create_params[:financial_transaction_type_id])
ft = current_ordergroup.add_financial_transaction!(create_params[:amount], create_params[:note], current_user, transaction_type)
ft = current_ordergroup.add_financial_transaction!(create_params[:amount], create_params[:note], current_user,
transaction_type)
render json: ft
end

View file

@ -4,8 +4,8 @@ class Api::V1::User::GroupOrderArticlesController < Api::V1::BaseController
before_action -> { doorkeeper_authorize! 'group_orders:user' }
before_action :require_ordergroup
before_action :require_minimum_balance, only: [:create, :update] # destroy is ok
before_action :require_enough_apples, only: [:create, :update] # destroy is ok
before_action :require_minimum_balance, only: %i[create update] # destroy is ok
before_action :require_enough_apples, only: %i[create update] # destroy is ok
# @todo allow decreasing amounts when minimum balance isn't met
def index
@ -35,7 +35,8 @@ class Api::V1::User::GroupOrderArticlesController < Api::V1::BaseController
goa = nil
GroupOrderArticle.transaction do
goa = scope_for_update.includes(:group_order_article_quantities).find(params.require(:id))
goa.update_quantities((update_params[:quantity] || goa.quantity).to_i, (update_params[:tolerance] || goa.tolerance).to_i)
goa.update_quantities((update_params[:quantity] || goa.quantity).to_i,
(update_params[:tolerance] || goa.tolerance).to_i)
goa.order_article.update_results!
goa.group_order.update_price!
goa.group_order.update!(updated_by: current_user)

View file

@ -8,13 +8,13 @@ class Api::V1::User::OrdergroupController < Api::V1::BaseController
financial_overview: {
account_balance: ordergroup.account_balance.to_f,
available_funds: ordergroup.get_available_funds.to_f,
financial_transaction_class_sums: FinancialTransactionClass.sorted.map { |c|
financial_transaction_class_sums: FinancialTransactionClass.sorted.map do |c|
{
id: c.id,
name: c.display,
amount: ordergroup["sum_of_class_#{c.id}"].to_f
}
}
end
}
}
end

View file

@ -19,11 +19,11 @@ class ApplicationController < ActionController::Base
private
def set_user_last_activity
if current_user && (session[:last_activity] == nil || session[:last_activity] < 1.minutes.ago)
return unless current_user && (session[:last_activity].nil? || session[:last_activity] < 1.minute.ago)
current_user.update_attribute(:last_activity, Time.now)
session[:last_activity] = Time.now
end
end
# Many plugins can be turned on and off on the fly with a `use_` configuration option.
# To disable a controller in the plugin, you can use this as a `before_action`:
@ -64,10 +64,10 @@ class ApplicationController < ActionController::Base
end
def items_per_page
if params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 500
@per_page = params[:per_page].to_i
@per_page = if params[:per_page] && params[:per_page].to_i > 0 && params[:per_page].to_i <= 500
params[:per_page].to_i
else
@per_page = 20
20
end
end

View file

@ -4,17 +4,17 @@ class ArticleCategoriesController < ApplicationController
before_action :authenticate_article_meta
def create
create!(:notice => I18n.t('article_categories.create.notice')) { article_categories_path }
create!(notice: I18n.t('article_categories.create.notice')) { article_categories_path }
end
def update
update!(:notice => I18n.t('article_categories.update.notice')) { article_categories_path }
update!(notice: I18n.t('article_categories.update.notice')) { article_categories_path }
end
def destroy
destroy!
rescue => error
redirect_to article_categories_path, alert: I18n.t('article_categories.destroy.error', message: error.message)
rescue StandardError => e
redirect_to article_categories_path, alert: I18n.t('article_categories.destroy.error', message: e.message)
end
protected

View file

@ -2,24 +2,24 @@ class ArticlesController < ApplicationController
before_action :authenticate_article_meta, :find_supplier
def index
if params['sort']
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"
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
sort = "article_categories.name, articles.name"
'article_categories.name, articles.name'
end
@articles = Article.undeleted.where(supplier_id: @supplier, :type => nil).includes(:article_category).order(sort)
@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'
@ -32,42 +32,42 @@ class ArticlesController < ApplicationController
respond_to do |format|
format.html
format.js { render :layout => false }
format.js { render layout: false }
end
end
def new
@article = @supplier.articles.build(:tax => FoodsoftConfig[:tax_default])
render :layout => false
@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
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
render layout: false
else
render :action => 'new', :layout => false
render action: 'new', layout: false
end
end
def edit
@article = Article.find(params[:id])
render :action => 'new', :layout => false
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
render layout: false
else
render :action => 'new', :layout => false
render action: 'new', layout: false
end
end
@ -75,7 +75,7 @@ class ArticlesController < ApplicationController
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
render layout: false
end
# Renders a form for editing all articles from a supplier
@ -87,21 +87,19 @@ class ArticlesController < ApplicationController
def update_all
invalid_articles = false
begin
Article.transaction do
unless params[:articles].blank?
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 unless invalid_articles # Remember that there are validation errors
invalid_articles ||= true # Remember that there are validation errors
end
end
raise ActiveRecord::Rollback if invalid_articles # Rollback all changes
end
end
end
if invalid_articles
# An error has occurred, transaction has been rolled back.
@ -134,16 +132,15 @@ class ArticlesController < ApplicationController
end
end
# action succeded
redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page])
rescue => error
redirect_to supplier_articles_url(@supplier, :per_page => params[:per_page]),
:alert => I18n.t('errors.general_msg', :msg => error)
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
def upload; end
# Update articles from a spreadsheet
def parse_upload
@ -151,13 +148,15 @@ class ArticlesController < ApplicationController
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
@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')
redirect_to supplier_articles_path(@supplier),
notice: I18n.t('articles.controller.parse_upload.notice')
end
@ignored_article_count = 0
rescue => error
redirect_to upload_supplier_articles_path(@supplier), :alert => I18n.t('errors.general_msg', :msg => error.message)
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
@ -165,13 +164,14 @@ class ArticlesController < ApplicationController
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)
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
if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty?
redirect_to supplier_articles_path(@supplier), :notice => I18n.t('articles.controller.sync.notice')
end
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
@ -186,7 +186,7 @@ class ArticlesController < ApplicationController
# delete articles
begin
@outlisted_articles.each(&:mark_as_deleted)
rescue
rescue StandardError
# raises an exception when used in current order
has_error = true
end
@ -198,15 +198,15 @@ class ArticlesController < ApplicationController
raise ActiveRecord::Rollback if has_error
end
if !has_error
redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.update_sync.notice')
else
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
@ -218,18 +218,18 @@ class ArticlesController < ApplicationController
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
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] unless params[:article_category_id].blank?
if params[:direct] && !params[:article_category_id].blank? && @article.valid? && @article.save
render :action => 'create', :layout => false
@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
render action: 'new', layout: false
end
end

View file

@ -9,15 +9,19 @@ module Concerns::Auth
def current_user
# check if there is a valid session and return the logged-in user (its object)
if session[:user_id] && params[:foodcoop]
return unless session[:user_id] && params[:foodcoop]
# for shared-host installations. check if the cookie-subdomain fits to request.
@current_user ||= User.undeleted.find_by_id(session[:user_id]) if session[:scope] == FoodsoftConfig.scope
end
end
def deny_access
session[:return_to] = request.original_url
redirect_to root_url, alert: I18n.t('application.controller.error_denied', sign_in: ActionController::Base.helpers.link_to(t('application.controller.error_denied_sign_in'), login_path))
redirect_to root_url,
alert: I18n.t('application.controller.error_denied',
sign_in: ActionController::Base.helpers.link_to(
t('application.controller.error_denied_sign_in'), login_path
))
end
private
@ -47,12 +51,7 @@ module Concerns::Auth
def authenticate(role = 'any')
# Attempt to retrieve authenticated user from controller instance or session...
if !current_user
# No user at all: redirect to login page.
logout
session[:return_to] = request.original_url
redirect_to_login :alert => I18n.t('application.controller.error_authn')
else
if current_user
# We have an authenticated user, now check role...
# Roles gets the user through his memberships.
hasRole = case role
@ -73,6 +72,11 @@ module Concerns::Auth
else
deny_access
end
else
# No user at all: redirect to login page.
logout
session[:return_to] = request.original_url
redirect_to_login alert: I18n.t('application.controller.error_authn')
end
end
@ -116,13 +120,13 @@ module Concerns::Auth
# if fails the user will redirected to startpage
def authenticate_membership_or_admin(group_id = params[:id])
@group = Group.find(group_id)
unless @group.member?(@current_user) || @current_user.role_admin?
return if @group.member?(@current_user) || @current_user.role_admin?
redirect_to root_path, alert: I18n.t('application.controller.error_members_only')
end
end
def authenticate_or_token(prefix, role = 'any')
if not params[:token].blank?
if params[:token].present?
begin
TokenVerifier.new(prefix).verify(params[:token])
rescue ActiveSupport::MessageVerifier::InvalidSignature

View file

@ -36,9 +36,9 @@ module Concerns::AuthApi
# Make sure that at least one the given OAuth scopes is valid for the current user's permissions.
# @raise Api::Errors::PermissionsRequired
def doorkeeper_authorize_roles!(*scopes)
unless scopes.any? { |scope| doorkeeper_scope_permitted?(scope) }
raise Api::Errors::PermissionRequired.new('Forbidden, no permission')
end
return if scopes.any? { |scope| doorkeeper_scope_permitted?(scope) }
raise Api::Errors::PermissionRequired, 'Forbidden, no permission'
end
# Check whether a given OAuth scope is permitted for the current user.
@ -48,9 +48,7 @@ module Concerns::AuthApi
def doorkeeper_scope_permitted?(scope)
scope_parts = scope.split(':')
# user sub-scopes like +config:user+ are always permitted
if scope_parts.last == 'user'
return true
end
return true if scope_parts.last == 'user'
case scope_parts.first
when 'user' then return true # access to the current user's own profile
@ -64,8 +62,8 @@ module Concerns::AuthApi
end
case scope
when 'orders:read' then return true
when 'orders:write' then return current_user.role_orders?
when 'orders:read' then true
when 'orders:write' then current_user.role_orders?
end
end
end

View file

@ -24,12 +24,12 @@ module Concerns::FoodcoopScope
elsif FoodsoftConfig.allowed_foodcoop? foodcoop
FoodsoftConfig.select_foodcoop foodcoop
else
raise ActionController::RoutingError.new 'Foodcoop Not Found'
raise ActionController::RoutingError, 'Foodcoop Not Found'
end
end
# Always stay in foodcoop url scope
def default_url_options(options = {})
def default_url_options(_options = {})
super().merge({ foodcoop: FoodsoftConfig.scope })
end
end

View file

@ -18,7 +18,7 @@ module Concerns::Locale
end
def browser_language
request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first : nil
request.env['HTTP_ACCEPT_LANGUAGE']&.scan(/^[a-z]{2}/)&.first
end
def default_language
@ -30,7 +30,7 @@ module Concerns::Locale
def select_language_according_to_priority
language = explicitly_requested_language || session_language || user_settings_language
language ||= browser_language unless FoodsoftConfig[:ignore_browser_locale]
language.presence&.to_sym unless language.blank?
language.presence&.to_sym if language.present?
end
def available_locales
@ -38,10 +38,10 @@ module Concerns::Locale
end
def set_locale
if available_locales.include?(select_language_according_to_priority)
::I18n.locale = select_language_according_to_priority
::I18n.locale = if available_locales.include?(select_language_according_to_priority)
select_language_according_to_priority
else
::I18n.locale = default_language
default_language
end
locale = session[:locale] = ::I18n.locale

View file

@ -3,7 +3,7 @@ module Concerns::SendOrderPdf
protected
def send_order_pdf order, document
def send_order_pdf(order, document)
klass = case document
when 'groups' then OrderByGroups
when 'articles' then OrderByArticles

View file

@ -1,5 +1,5 @@
class DeliveriesController < ApplicationController
before_action :find_supplier, :exclude => :fill_new_stock_article_form
before_action :find_supplier, exclude: :fill_new_stock_article_form
def index
@deliveries = @supplier.deliveries.order('date DESC')
@ -15,6 +15,10 @@ class DeliveriesController < ApplicationController
@delivery.date = Date.today # TODO: move to model/database
end
def edit
@delivery = Delivery.find(params[:id])
end
def create
@delivery = Delivery.new(params[:delivery])
@ -22,14 +26,10 @@ class DeliveriesController < ApplicationController
flash[:notice] = I18n.t('deliveries.create.notice')
redirect_to [@supplier, @delivery]
else
render :action => "new"
render action: 'new'
end
end
def edit
@delivery = Delivery.find(params[:id])
end
def update
@delivery = Delivery.find(params[:id])
@ -37,7 +37,7 @@ class DeliveriesController < ApplicationController
flash[:notice] = I18n.t('deliveries.update.notice')
redirect_to [@supplier, @delivery]
else
render :action => "edit"
render action: 'edit'
end
end
@ -52,18 +52,18 @@ class DeliveriesController < ApplicationController
def add_stock_change
@stock_change = StockChange.new
@stock_change.stock_article = StockArticle.find(params[:stock_article_id])
render :layout => false
render layout: false
end
def form_on_stock_article_create # See publish/subscribe design pattern in /doc.
@stock_article = StockArticle.find(params[:id])
render :layout => false
render layout: false
end
def form_on_stock_article_update # See publish/subscribe design pattern in /doc.
@stock_article = StockArticle.find(params[:id])
render :layout => false
render layout: false
end
end

View file

@ -1,13 +1,12 @@
class FeedbackController < ApplicationController
def new
end
def new; end
def create
if params[:message].present?
Mailer.feedback(current_user, params[:message]).deliver_now
redirect_to root_url, notice: t('feedback.create.notice')
redirect_to root_url, notice: t('.notice')
else
render :action => 'new'
render action: 'new'
end
end
end

View file

@ -5,7 +5,7 @@ class Finance::BalancingController < Finance::BaseController
def new
@order = Order.find(params[:order_id])
flash.now.alert = t('finance.balancing.new.alert') if @order.closed?
flash.now.alert = t('.alert') if @order.closed?
@comments = @order.comments
@articles = @order.order_articles.ordered_or_member.includes(:article, :article_price,
@ -13,13 +13,13 @@ class Finance::BalancingController < Finance::BaseController
sort_param = params['sort'] || 'name'
@articles = case sort_param
when 'name' then
when 'name'
@articles.order('articles.name ASC')
when 'name_reverse' then
when 'name_reverse'
@articles.order('articles.name DESC')
when 'order_number' then
when 'order_number'
@articles.order('articles.order_number ASC')
when 'order_number_reverse' then
when 'order_number_reverse'
@articles.order('articles.order_number DESC')
else
@articles
@ -31,13 +31,13 @@ class Finance::BalancingController < Finance::BaseController
def new_on_order_article_create # See publish/subscribe design pattern in /doc.
@order_article = OrderArticle.find(params[:order_article_id])
render :layout => false
render layout: false
end
def new_on_order_article_update # See publish/subscribe design pattern in /doc.
@order_article = OrderArticle.find(params[:order_article_id])
render :layout => false
render layout: false
end
def update_summary
@ -46,29 +46,29 @@ class Finance::BalancingController < Finance::BaseController
def edit_note
@order = Order.find(params[:id])
render :layout => false
render layout: false
end
def update_note
@order = Order.find(params[:id])
if @order.update(params[:order])
render :layout => false
render layout: false
else
render :action => :edit_note, :layout => false
render action: :edit_note, layout: false
end
end
def edit_transport
@order = Order.find(params[:id])
render :layout => false
render layout: false
end
def update_transport
@order = Order.find(params[:id])
@order.update!(params[:order])
redirect_to new_finance_order_path(order_id: @order.id)
rescue => error
redirect_to new_finance_order_path(order_id: @order.id), alert: t('errors.general_msg', msg: error.message)
rescue StandardError => e
redirect_to new_finance_order_path(order_id: @order.id), alert: t('errors.general_msg', msg: e.message)
end
# before the order will booked, a view lists all Ordergroups and its order_prices
@ -81,18 +81,18 @@ class Finance::BalancingController < Finance::BaseController
@order = Order.find(params[:id])
@type = FinancialTransactionType.find_by_id(params.permit(:type)[:type])
@order.close!(@current_user, @type)
redirect_to finance_order_index_url, notice: t('finance.balancing.close.notice')
rescue => error
redirect_to new_finance_order_url(order_id: @order.id), alert: t('finance.balancing.close.alert', message: error.message)
redirect_to finance_order_index_url, notice: t('.notice')
rescue StandardError => e
redirect_to new_finance_order_url(order_id: @order.id), alert: t('.alert', message: e.message)
end
# Close the order directly, without automaticly updating ordergroups account balances
def close_direct
@order = Order.find(params[:id])
@order.close_direct!(@current_user)
redirect_to finance_order_index_url, notice: t('finance.balancing.close_direct.notice')
rescue => error
redirect_to finance_order_index_url, alert: t('finance.balancing.close_direct.alert', message: error.message)
redirect_to finance_order_index_url, notice: t('.notice')
rescue StandardError => e
redirect_to finance_order_index_url, alert: t('.alert', message: e.message)
end
def close_all_direct_with_invoice
@ -103,8 +103,8 @@ class Finance::BalancingController < Finance::BaseController
count += 1
end
end
redirect_to finance_order_index_url, notice: t('finance.balancing.close_all_direct_with_invoice.notice', count: count)
rescue => error
redirect_to finance_order_index_url, alert: t('errors.general_msg', msg: error.message)
redirect_to finance_order_index_url, notice: t('.notice', count: count)
rescue StandardError => e
redirect_to finance_order_index_url, alert: t('errors.general_msg', msg: e.message)
end
end

View file

@ -8,8 +8,8 @@ class Finance::BankAccountsController < Finance::BaseController
@bank_account = BankAccount.find(params[:id])
count = @bank_account.assign_unlinked_transactions
redirect_to finance_bank_account_transactions_url(@bank_account), notice: t('.notice', count: count)
rescue => error
redirect_to finance_bank_account_transactions_url(@bank_account), alert: t('errors.general_msg', msg: error.message)
rescue StandardError => e
redirect_to finance_bank_account_transactions_url(@bank_account), alert: t('errors.general_msg', msg: e.message)
end
def import
@ -33,8 +33,8 @@ class Finance::BankAccountsController < Finance::BaseController
end
needs_redirect = ok
rescue => error
flash.alert = t('errors.general_msg', msg: error.message)
rescue StandardError => e
flash.alert = t('errors.general_msg', msg: e.message)
needs_redirect = true
ensure
return unless needs_redirect

View file

@ -3,26 +3,30 @@ class Finance::BankTransactionsController < ApplicationController
inherit_resources
def index
if params["sort"]
sort = case params["sort"]
when "date" then "date"
when "amount" then "amount"
when "financial_link" then "financial_link_id"
when "date_reverse" then "date DESC"
when "amount_reverse" then "amount DESC"
when "financial_link_reverse" then "financial_link_id DESC"
sort = if params['sort']
case params['sort']
when 'date' then 'date'
when 'amount' then 'amount'
when 'financial_link' then 'financial_link_id'
when 'date_reverse' then 'date DESC'
when 'amount_reverse' then 'amount DESC'
when 'financial_link_reverse' then 'financial_link_id DESC'
end
else
sort = "date DESC"
'date DESC'
end
@bank_account = BankAccount.find(params[:bank_account_id])
@bank_transactions_all = @bank_account.bank_transactions.order(sort).includes(:financial_link)
@bank_transactions_all = @bank_transactions_all.where('reference LIKE ? OR text LIKE ?', "%#{params[:query]}%", "%#{params[:query]}%") unless params[:query].nil?
unless params[:query].nil?
@bank_transactions_all = @bank_transactions_all.where('reference LIKE ? OR text LIKE ?', "%#{params[:query]}%",
"%#{params[:query]}%")
end
@bank_transactions = @bank_transactions_all.page(params[:page]).per(@per_page)
respond_to do |format|
format.js; format.html { render }
format.js
format.html { render }
format.csv do
send_data BankTransactionsCsv.new(@bank_transactions_all).to_csv, filename: 'transactions.csv', type: 'text/csv'
end

View file

@ -1,5 +1,5 @@
class Finance::FinancialLinksController < Finance::BaseController
before_action :find_financial_link, except: [:create, :incomplete]
before_action :find_financial_link, except: %i[create incomplete]
def show
@items = @financial_link.bank_transactions.map do |bt|
@ -37,7 +37,7 @@ class Finance::FinancialLinksController < Finance::BaseController
def create
@financial_link = FinancialLink.first_unused_or_create
if params[:bank_transaction] then
if params[:bank_transaction]
bank_transaction = BankTransaction.find(params[:bank_transaction])
bank_transaction.update_attribute :financial_link, @financial_link
end
@ -72,14 +72,16 @@ class Finance::FinancialLinksController < Finance::BaseController
def create_financial_transaction
financial_transaction = FinancialTransaction.new(financial_transaction_params)
financial_transaction.ordergroup.add_financial_transaction! financial_transaction.amount, financial_transaction.note, current_user, financial_transaction.financial_transaction_type, @financial_link
financial_transaction.ordergroup.add_financial_transaction! financial_transaction.amount,
financial_transaction.note, current_user, financial_transaction.financial_transaction_type, @financial_link
redirect_to finance_link_url(@financial_link), notice: t('.notice')
rescue => error
redirect_to finance_link_url(@financial_link), alert: t('errors.general_msg', msg: error)
rescue StandardError => e
redirect_to finance_link_url(@financial_link), alert: t('errors.general_msg', msg: e)
end
def index_financial_transaction
@financial_transactions = FinancialTransaction.without_financial_link.includes(:financial_transaction_type, :ordergroup)
@financial_transactions = FinancialTransaction.without_financial_link.includes(:financial_transaction_type,
:ordergroup)
end
def add_financial_transaction
@ -123,7 +125,7 @@ class Finance::FinancialLinksController < Finance::BaseController
end
def find_best_fitting_ordergroup_id_for_financial_link(financial_link_id)
FinancialTransaction.joins(<<-SQL).order(created_on: :desc).pluck(:ordergroup_id).first
FinancialTransaction.joins(<<-SQL).order(created_on: :desc).pick(:ordergroup_id)
JOIN bank_transactions a ON financial_transactions.financial_link_id = a.financial_link_id
JOIN bank_transactions b ON a.iban = b.iban AND b.financial_link_id = #{financial_link_id.to_i}
SQL

View file

@ -1,21 +1,21 @@
class Finance::FinancialTransactionsController < ApplicationController
before_action :authenticate_finance
before_action :find_ordergroup, :except => [:new_collection, :create_collection, :index_collection]
before_action :find_ordergroup, except: %i[new_collection create_collection index_collection]
inherit_resources
# belongs_to :ordergroup
def index
if params['sort']
sort = case params['sort']
when "date" then "created_on"
when "note" then "note"
when "amount" then "amount"
when "date_reverse" then "created_on DESC"
when "note_reverse" then "note DESC"
when "amount_reverse" then "amount DESC"
sort = if params['sort']
case params['sort']
when 'date' then 'created_on'
when 'note' then 'note'
when 'amount' then 'amount'
when 'date_reverse' then 'created_on DESC'
when 'note_reverse' then 'note DESC'
when 'amount_reverse' then 'amount DESC'
end
else
sort = "created_on DESC"
'created_on DESC'
end
@q = FinancialTransaction.ransack(params[:q])
@ -26,9 +26,11 @@ class Finance::FinancialTransactionsController < ApplicationController
@financial_transactions = @financial_transactions_all.page(params[:page]).per(@per_page)
respond_to do |format|
format.js; format.html { render }
format.js
format.html { render }
format.csv do
send_data FinancialTransactionsCsv.new(@financial_transactions_all).to_csv, filename: 'transactions.csv', type: 'text/csv'
send_data FinancialTransactionsCsv.new(@financial_transactions_all).to_csv, filename: 'transactions.csv',
type: 'text/csv'
end
end
end
@ -38,10 +40,10 @@ class Finance::FinancialTransactionsController < ApplicationController
end
def new
if @ordergroup
@financial_transaction = @ordergroup.financial_transactions.build
@financial_transaction = if @ordergroup
@ordergroup.financial_transactions.build
else
@financial_transaction = FinancialTransaction.new
FinancialTransaction.new
end
end
@ -53,16 +55,18 @@ class Finance::FinancialTransactionsController < ApplicationController
else
@financial_transaction.save!
end
redirect_to finance_group_transactions_path(@ordergroup), notice: I18n.t('finance.financial_transactions.controller.create.notice')
rescue ActiveRecord::RecordInvalid => error
flash.now[:alert] = error.message
render :action => :new
redirect_to finance_group_transactions_path(@ordergroup),
notice: I18n.t('finance.financial_transactions.controller.create.notice')
rescue ActiveRecord::RecordInvalid => e
flash.now[:alert] = e.message
render action: :new
end
def destroy
transaction = FinancialTransaction.find(params[:id])
transaction.revert!(current_user)
redirect_to finance_group_transactions_path(transaction.ordergroup), notice: t('finance.financial_transactions.controller.destroy.notice')
redirect_to finance_group_transactions_path(transaction.ordergroup),
notice: t('finance.financial_transactions.controller.destroy.notice')
end
def new_collection
@ -88,7 +92,8 @@ class Finance::FinancialTransactionsController < ApplicationController
params[:financial_transactions].each do |trans|
# ignore empty amount fields ...
unless trans[:amount].blank?
next if trans[:amount].blank?
amount = LocalizeInput.parse(trans[:amount]).to_f
note = params[:note]
ordergroup = Ordergroup.find(trans[:ordergroup_id])
@ -99,7 +104,6 @@ class Finance::FinancialTransactionsController < ApplicationController
ordergroup.add_financial_transaction!(amount, note, @current_user, type, financial_link)
foodcoop_amount -= amount
end
end
if params[:create_foodcoop_transaction]
ft = FinancialTransaction.new({
@ -107,7 +111,7 @@ class Finance::FinancialTransactionsController < ApplicationController
user: @current_user,
amount: foodcoop_amount,
note: params[:note],
financial_link: financial_link,
financial_link: financial_link
})
ft.save!
end
@ -117,8 +121,8 @@ class Finance::FinancialTransactionsController < ApplicationController
url = financial_link ? finance_link_url(financial_link.id) : finance_ordergroups_url
redirect_to url, notice: I18n.t('finance.financial_transactions.controller.create_collection.notice')
rescue => error
flash.now[:alert] = error.message
rescue StandardError => e
flash.now[:alert] = e.message
render action: :new_collection
end

View file

@ -1,15 +1,16 @@
class Finance::InvoicesController < ApplicationController
before_action :authenticate_finance_or_invoices
before_action :find_invoice, only: [:show, :edit, :update, :destroy]
before_action :ensure_can_edit, only: [:edit, :update, :destroy]
before_action :find_invoice, only: %i[show edit update destroy]
before_action :ensure_can_edit, only: %i[edit update destroy]
def index
@invoices_all = Invoice.includes(:supplier, :deliveries, :orders).order('date DESC')
@invoices = @invoices_all.page(params[:page]).per(@per_page)
respond_to do |format|
format.js; format.html { render }
format.js
format.html { render }
format.csv do
send_data InvoicesCsv.new(@invoices_all).to_csv, filename: 'invoices.csv', type: 'text/csv'
end
@ -20,11 +21,10 @@ class Finance::InvoicesController < ApplicationController
@suppliers = Supplier.includes(:invoices).where('invoices.paid_on IS NULL').references(:invoices)
end
def show
end
def show; end
def new
@invoice = Invoice.new :supplier_id => params[:supplier_id]
@invoice = Invoice.new supplier_id: params[:supplier_id]
@invoice.deliveries << Delivery.find_by_id(params[:delivery_id]) if params[:delivery_id]
@invoice.orders << Order.find_by_id(params[:order_id]) if params[:order_id]
fill_deliveries_and_orders_collection @invoice.id, @invoice.supplier_id
@ -36,12 +36,14 @@ class Finance::InvoicesController < ApplicationController
def form_on_supplier_id_change
fill_deliveries_and_orders_collection params[:invoice_id], params[:supplier_id]
render :layout => false
render layout: false
end
def fill_deliveries_and_orders_collection(invoice_id, supplier_id)
@deliveries_collection = Delivery.where('invoice_id = ? OR (invoice_id IS NULL AND supplier_id = ?)', invoice_id, supplier_id).order(date: :desc).limit(25)
@orders_collection = Order.where('invoice_id = ? OR (invoice_id IS NULL AND supplier_id = ?)', invoice_id, supplier_id).order(ends: :desc).limit(25)
@deliveries_collection = Delivery.where('invoice_id = ? OR (invoice_id IS NULL AND supplier_id = ?)', invoice_id,
supplier_id).order(date: :desc).limit(25)
@orders_collection = Order.where('invoice_id = ? OR (invoice_id IS NULL AND supplier_id = ?)', invoice_id,
supplier_id).order(ends: :desc).limit(25)
end
def create
@ -58,7 +60,7 @@ class Finance::InvoicesController < ApplicationController
end
else
fill_deliveries_and_orders_collection @invoice.id, @invoice.supplier_id
render :action => "new"
render action: 'new'
end
end
@ -81,7 +83,7 @@ class Finance::InvoicesController < ApplicationController
@invoice = Invoice.find(params[:invoice_id])
type = MIME::Types[@invoice.attachment_mime].first
filename = "invoice_#{@invoice.id}_attachment.#{type.preferred_extension}"
send_data(@invoice.attachment_data, :filename => filename, :type => type)
send_data(@invoice.attachment_data, filename: filename, type: type)
end
private
@ -92,8 +94,8 @@ class Finance::InvoicesController < ApplicationController
# Returns true if @current_user can edit the invoice..
def ensure_can_edit
unless @invoice.user_can_edit?(current_user)
return if @invoice.user_can_edit?(current_user)
deny_access
end
end
end

View file

@ -1,11 +1,11 @@
class Finance::OrdergroupsController < Finance::BaseController
def index
m = /^(?<col>name|sum_of_class_\d+)(?<reverse>_reverse)?$/.match params["sort"]
m = /^(?<col>name|sum_of_class_\d+)(?<reverse>_reverse)?$/.match params['sort']
if m
sort = m[:col]
sort += ' DESC' if m[:reverse]
else
sort = "name"
sort = 'name'
end
@ordergroups = Ordergroup.undeleted.order(sort)

View file

@ -1,20 +1,16 @@
class Foodcoop::OrdergroupsController < ApplicationController
def index
@ordergroups = Ordergroup.undeleted.sort_by_param(params["sort"])
@ordergroups = Ordergroup.undeleted.sort_by_param(params['sort'])
unless params[:name].blank? # Search by name
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%")
end
@ordergroups = @ordergroups.where('name LIKE ?', "%#{params[:name]}%") if params[:name].present? # Search by name
if params[:only_active] # Select only active groups
@ordergroups = @ordergroups.active
end
@ordergroups = @ordergroups.active if params[:only_active] # Select only active groups
@ordergroups = @ordergroups.page(params[:page]).per(@per_page)
respond_to do |format|
format.html # index.html.erb
format.js { render :layout => false }
format.js { render layout: false }
end
end
end

View file

@ -1,19 +1,20 @@
class Foodcoop::UsersController < ApplicationController
def index
@users = User.undeleted.sort_by_param(params["sort"])
@users = User.undeleted.sort_by_param(params['sort'])
# if somebody uses the search field:
@users = @users.natural_search(params[:user_name]) unless params[:user_name].blank?
@users = @users.natural_search(params[:user_name]) if params[:user_name].present?
if params[:ordergroup_name]
@users = @users.joins(:groups).where("groups.type = 'Ordergroup' AND groups.name LIKE ?", "%#{params[:ordergroup_name]}%")
@users = @users.joins(:groups).where("groups.type = 'Ordergroup' AND groups.name LIKE ?",
"%#{params[:ordergroup_name]}%")
end
@users = @users.page(params[:page]).per(@per_page)
respond_to do |format|
format.html # index.html.haml
format.js { render :layout => false } # index.js.erb
format.js { render layout: false } # index.js.erb
end
end
end

View file

@ -1,9 +1,9 @@
class Foodcoop::WorkgroupsController < ApplicationController
before_action :authenticate_membership_or_admin,
:except => [:index]
except: [:index]
def index
@workgroups = Workgroup.order("name")
@workgroups = Workgroup.order('name')
end
def edit
@ -13,9 +13,9 @@ class Foodcoop::WorkgroupsController < ApplicationController
def update
@workgroup = Workgroup.find(params[:id])
if @workgroup.update(params[:workgroup])
redirect_to foodcoop_workgroups_url, :notice => I18n.t('workgroups.update.notice')
redirect_to foodcoop_workgroups_url, notice: I18n.t('workgroups.update.notice')
else
render :action => 'edit'
render action: 'edit'
end
end
end

View file

@ -1,6 +1,6 @@
class GroupOrderArticlesController < ApplicationController
before_action :authenticate_finance
before_action :find_group_order_article, except: [:new, :create]
before_action :find_group_order_article, except: %i[new create]
layout false # We only use this controller to server js snippets, no need for layout rendering

View file

@ -3,9 +3,9 @@
class GroupOrdersController < ApplicationController
# Security
before_action :ensure_ordergroup_member
before_action :ensure_open_order, :only => [:new, :create, :edit, :update, :order, :stock_order, :saveOrder]
before_action :ensure_my_group_order, only: [:show, :edit, :update]
before_action :enough_apples?, only: [:new, :create]
before_action :ensure_open_order, only: %i[new create edit update order stock_order saveOrder]
before_action :ensure_my_group_order, only: %i[show edit update]
before_action :enough_apples?, only: %i[new create]
# Index page.
def index
@ -13,9 +13,17 @@ class GroupOrdersController < ApplicationController
@finished_not_closed_orders_including_group_order = Order.finished_not_closed.ordergroup_group_orders_map(@ordergroup)
end
def show
@order = @group_order.order
end
def new
ordergroup = params[:stock_order] ? nil : @ordergroup
@group_order = @order.group_orders.build(:ordergroup => ordergroup, :updated_by => current_user)
@group_order = @order.group_orders.build(ordergroup: ordergroup, updated_by: current_user)
@ordering_data = @group_order.load_data
end
def edit
@ordering_data = @group_order.load_data
end
@ -23,34 +31,26 @@ class GroupOrdersController < ApplicationController
@group_order = GroupOrder.new(params[:group_order])
begin
@group_order.save_ordering!
redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.create.notice')
redirect_to group_order_url(@group_order), notice: I18n.t('group_orders.create.notice')
rescue ActiveRecord::StaleObjectError
redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_stale')
rescue => exception
logger.error('Failed to update order: ' + exception.message)
redirect_to group_orders_url, :alert => I18n.t('group_orders.create.error_general')
redirect_to group_orders_url, alert: I18n.t('group_orders.create.error_stale')
rescue StandardError => e
logger.error('Failed to update order: ' + e.message)
redirect_to group_orders_url, alert: I18n.t('group_orders.create.error_general')
end
end
def show
@order = @group_order.order
end
def edit
@ordering_data = @group_order.load_data
end
def update
@group_order.attributes = params[:group_order]
@group_order.updated_by = current_user
begin
@group_order.save_ordering!
redirect_to group_order_url(@group_order), :notice => I18n.t('group_orders.update.notice')
redirect_to group_order_url(@group_order), notice: I18n.t('group_orders.update.notice')
rescue ActiveRecord::StaleObjectError
redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_stale')
rescue => exception
logger.error('Failed to update order: ' + exception.message)
redirect_to group_orders_url, :alert => I18n.t('group_orders.update.error_general')
redirect_to group_orders_url, alert: I18n.t('group_orders.update.error_stale')
rescue StandardError => e
logger.error('Failed to update order: ' + e.message)
redirect_to group_orders_url, alert: I18n.t('group_orders.update.error_general')
end
end
@ -74,16 +74,16 @@ class GroupOrdersController < ApplicationController
# Used as a :before_action by OrdersController.
def ensure_ordergroup_member
@ordergroup = @current_user.ordergroup
if @ordergroup.nil?
redirect_to root_url, :alert => I18n.t('group_orders.errors.no_member')
end
return unless @ordergroup.nil?
redirect_to root_url, alert: I18n.t('group_orders.errors.no_member')
end
def ensure_open_order
@order = Order.includes([:supplier, :order_articles]).find(order_id_param)
@order = Order.includes(%i[supplier order_articles]).find(order_id_param)
unless @order.open?
flash[:notice] = I18n.t('group_orders.errors.closed')
redirect_to :action => 'index'
redirect_to action: 'index'
end
rescue ActiveRecord::RecordNotFound
redirect_to group_orders_url, alert: I18n.t('group_orders.errors.notfound')
@ -91,18 +91,18 @@ class GroupOrdersController < ApplicationController
def ensure_my_group_order
@group_order = GroupOrder.find(params[:id])
if @group_order.ordergroup != @ordergroup && (@group_order.ordergroup || !current_user.role_orders?)
return unless @group_order.ordergroup != @ordergroup && (@group_order.ordergroup || !current_user.role_orders?)
redirect_to group_orders_url, alert: I18n.t('group_orders.errors.notfound')
end
end
def enough_apples?
if @ordergroup.not_enough_apples?
return unless @ordergroup.not_enough_apples?
redirect_to group_orders_url,
alert: t('not_enough_apples', scope: 'group_orders.messages', apples: @ordergroup.apples,
stop_ordering_under: FoodsoftConfig[:stop_ordering_under])
end
end
def order_id_param
params[:order_id] || (params[:group_order] && params[:group_order][:order_id])

View file

@ -9,8 +9,7 @@ class HomeController < ApplicationController
@unassigned_tasks = Task.order(:due_date).next_unassigned_tasks_for(current_user)
end
def profile
end
def profile; end
def reference_calculator
if current_user.ordergroup
@ -36,40 +35,43 @@ class HomeController < ApplicationController
@user = @current_user
@ordergroup = @user.ordergroup
unless @ordergroup.nil?
if @ordergroup.nil?
redirect_to root_path, alert: I18n.t('home.no_ordergroups')
else
@ordergroup = Ordergroup.include_transaction_class_sum.find(@ordergroup.id)
if params['sort']
sort = case params['sort']
when "date" then "created_on"
when "note" then "note"
when "amount" then "amount"
when "date_reverse" then "created_on DESC"
when "note_reverse" then "note DESC"
when "amount_reverse" then "amount DESC"
sort = if params['sort']
case params['sort']
when 'date' then 'created_on'
when 'note' then 'note'
when 'amount' then 'amount'
when 'date_reverse' then 'created_on DESC'
when 'note_reverse' then 'note DESC'
when 'amount_reverse' then 'amount DESC'
end
else
sort = "created_on DESC"
'created_on DESC'
end
@financial_transactions = @ordergroup.financial_transactions.visible.page(params[:page]).per(@per_page).order(sort)
@financial_transactions = @financial_transactions.where('financial_transactions.note LIKE ?', "%#{params[:query]}%") if params[:query].present?
if params[:query].present?
@financial_transactions = @financial_transactions.where('financial_transactions.note LIKE ?',
"%#{params[:query]}%")
end
else
redirect_to root_path, alert: I18n.t('home.no_ordergroups')
end
end
# cancel personal memberships direct from the myProfile-page
def cancel_membership
if params[:membership_id]
membership = @current_user.memberships.find(params[:membership_id])
membership = if params[:membership_id]
@current_user.memberships.find(params[:membership_id])
else
membership = @current_user.memberships.find_by_group_id!(params[:group_id])
@current_user.memberships.find_by_group_id!(params[:group_id])
end
membership.destroy
redirect_to my_profile_path, notice: I18n.t('home.ordergroup_cancelled', :group => membership.group.name)
redirect_to my_profile_path, notice: I18n.t('home.ordergroup_cancelled', group: membership.group.name)
end
protected
@ -82,8 +84,8 @@ class HomeController < ApplicationController
end
def ordergroup_params
if params[:user][:ordergroup]
return unless params[:user][:ordergroup]
params.require(:user).require(:ordergroup).permit(:contact_address)
end
end
end

View file

@ -3,7 +3,7 @@ class InvitesController < ApplicationController
before_action -> { require_config_disabled :disable_invite }
def new
@invite = Invite.new(:user => @current_user, :group => @group)
@invite = Invite.new(user: @current_user, group: @group)
end
def create
@ -27,6 +27,10 @@ class InvitesController < ApplicationController
protected
def authenticate_membership_or_admin_for_invites
authenticate_membership_or_admin((params[:invite][:group_id] rescue params[:id]))
authenticate_membership_or_admin(begin
params[:invite][:group_id]
rescue StandardError
params[:id]
end)
end
end

View file

@ -1,6 +1,6 @@
class LoginController < ApplicationController
skip_before_action :authenticate # no authentication since this is the login page
before_action :validate_token, :only => [:new_password, :update_password]
before_action :validate_token, only: %i[new_password update_password]
# Display the form to enter an email address requesting a token to set a new password.
def forgot_password
@ -9,20 +9,17 @@ class LoginController < ApplicationController
# Sends an email to a user with the token that allows setting a new password through action "password".
def reset_password
if request.get? || params[:user].nil? # Catch for get request and give better error message.
redirect_to forgot_password_url, alert: I18n.t('errors.general_again') and return
end
redirect_to forgot_password_url, alert: I18n.t('errors.general_again') and return if request.get? || params[:user].nil? # Catch for get request and give better error message.
if (user = User.undeleted.find_by_email(params[:user][:email]))
user.request_password_reset!
end
redirect_to login_url, :notice => I18n.t('login.controller.reset_password.notice')
redirect_to login_url, notice: I18n.t('login.controller.reset_password.notice')
end
# Set a new password with a token from the password reminder email.
# Called with params :id => User.id and :token => User.reset_password_token to specify a new password.
def new_password
end
def new_password; end
# Sets a new password.
# Called with params :id => User.id and :token => User.reset_password_token to specify a new password.
@ -32,7 +29,7 @@ class LoginController < ApplicationController
@user.reset_password_token = nil
@user.reset_password_expires = nil
@user.save
redirect_to login_url, :notice => I18n.t('login.controller.update_password.notice')
redirect_to login_url, notice: I18n.t('login.controller.update_password.notice')
else
render :new_password
end
@ -50,14 +47,14 @@ class LoginController < ApplicationController
@user = User.new(params[:user])
@user.email = @invite.email
if @user.save
Membership.new(:user => @user, :group => @invite.group).save!
Membership.new(user: @user, group: @invite.group).save!
@invite.destroy
session[:locale] = @user.locale
redirect_to login_url, notice: I18n.t('login.controller.accept_invitation.notice')
end
end
else
@user = User.new(:email => @invite.email)
@user = User.new(email: @invite.email)
end
end
@ -65,8 +62,8 @@ class LoginController < ApplicationController
def validate_token
@user = User.find_by_id_and_reset_password_token(params[:id], params[:token])
if (@user.nil? || @user.reset_password_expires < Time.now)
return unless @user.nil? || @user.reset_password_expires < Time.now
redirect_to forgot_password_url, alert: I18n.t('login.controller.error_token_invalid')
end
end
end

View file

@ -1,7 +1,7 @@
class OrderArticlesController < ApplicationController
before_action :fetch_order, except: :destroy
before_action :authenticate_finance_or_invoices, except: [:new, :create]
before_action :authenticate_finance_orders_or_pickup, except: [:edit, :update, :destroy]
before_action :authenticate_finance_or_invoices, except: %i[new create]
before_action :authenticate_finance_orders_or_pickup, except: %i[edit update destroy]
layout false # We only use this controller to serve js snippets, no need for layout rendering
@ -9,28 +9,26 @@ class OrderArticlesController < ApplicationController
@order_article = @order.order_articles.build(params[:order_article])
end
def edit
@order_article = OrderArticle.find(params[:id])
end
def create
# The article may be ordered with zero units - in that case do not complain.
# If order_article is ordered and a new order_article is created, an error message will be
# given mentioning that the article already exists, which is desired.
@order_article = @order.order_articles.where(:article_id => params[:order_article][:article_id]).first
unless @order_article && @order_article.units_to_order == 0
@order_article = @order.order_articles.build(params[:order_article])
end
@order_article = @order.order_articles.where(article_id: params[:order_article][:article_id]).first
@order_article = @order.order_articles.build(params[:order_article]) unless @order_article && @order_article.units_to_order == 0
@order_article.save!
rescue
rescue StandardError
render action: :new
end
def edit
@order_article = OrderArticle.find(params[:id])
end
def update
@order_article = OrderArticle.find(params[:id])
begin
@order_article.update_article_and_price!(params[:order_article], params[:article], params[:article_price])
rescue
rescue StandardError
render action: :edit
end
end

View file

@ -1,15 +1,15 @@
class OrderCommentsController < ApplicationController
def new
@order = Order.find(params[:order_id])
@order_comment = @order.comments.build(:user => current_user)
@order_comment = @order.comments.build(user: current_user)
end
def create
@order_comment = OrderComment.new(params[:order_comment])
if @order_comment.save
render :layout => false
render layout: false
else
render :action => :new, :layout => false
render action: :new, layout: false
end
end
end

View file

@ -5,24 +5,25 @@ class OrdersController < ApplicationController
include Concerns::SendOrderPdf
before_action :authenticate_pickups_or_orders
before_action :authenticate_orders, except: [:receive, :receive_on_order_article_create, :receive_on_order_article_update, :show]
before_action :remove_empty_article, only: [:create, :update]
before_action :authenticate_orders,
except: %i[receive receive_on_order_article_create receive_on_order_article_update show]
before_action :remove_empty_article, only: %i[create update]
# List orders
def index
@open_orders = Order.open.includes(:supplier)
@finished_orders = Order.finished_not_closed.includes(:supplier)
@per_page = 15
if params['sort']
sort = case params['sort']
when "supplier" then "suppliers.name, ends DESC"
when "pickup" then "pickup DESC"
when "ends" then "ends DESC"
when "supplier_reverse" then "suppliers.name DESC"
when "ends_reverse" then "ends"
sort = if params['sort']
case params['sort']
when 'supplier' then 'suppliers.name, ends DESC'
when 'pickup' then 'pickup DESC'
when 'ends' then 'ends DESC'
when 'supplier_reverse' then 'suppliers.name DESC'
when 'ends_reverse' then 'ends'
end
else
sort = "ends DESC"
'ends DESC'
end
@suppliers = Supplier.having_articles.order('suppliers.name')
@orders = Order.closed.includes(:supplier).reorder(sort).page(params[:page]).per(@per_page)
@ -43,7 +44,7 @@ class OrdersController < ApplicationController
respond_to do |format|
format.html
format.js do
render :layout => false
render layout: false
end
format.pdf do
send_order_pdf @order, params[:document]
@ -66,8 +67,14 @@ class OrdersController < ApplicationController
else
@order = Order.new(supplier_id: params[:supplier_id]).init_dates
end
rescue => error
redirect_to orders_url, alert: t('errors.general_msg', msg: error.message)
rescue StandardError => e
redirect_to orders_url, alert: t('errors.general_msg', msg: e.message)
end
# Page to edit an exsiting order.
# editing finished orders is done in FinanceController
def edit
@order = Order.includes(:articles).find(params[:id])
end
# Save a new order.
@ -81,31 +88,25 @@ class OrdersController < ApplicationController
redirect_to @order
else
logger.debug "[debug] order errors: #{@order.errors.messages}"
render :action => 'new'
render action: 'new'
end
end
# Page to edit an exsiting order.
# editing finished orders is done in FinanceController
def edit
@order = Order.includes(:articles).find(params[:id])
end
# Update an existing order.
def update
@order = Order.find params[:id]
if @order.update(params[:order].merge(updated_by: current_user))
flash[:notice] = I18n.t('orders.update.notice')
redirect_to :action => 'show', :id => @order
redirect_to action: 'show', id: @order
else
render :action => 'edit'
render action: 'edit'
end
end
# Delete an order.
def destroy
Order.find(params[:id]).destroy
redirect_to :action => 'index'
redirect_to action: 'index'
end
# Finish a current order.
@ -113,8 +114,8 @@ class OrdersController < ApplicationController
order = Order.find(params[:id])
order.finish!(@current_user)
redirect_to order, notice: I18n.t('orders.finish.notice')
rescue => error
redirect_to orders_url, alert: I18n.t('errors.general_msg', :msg => error.message)
rescue StandardError => e
redirect_to orders_url, alert: I18n.t('errors.general_msg', msg: e.message)
end
# Send a order to the supplier.
@ -122,20 +123,18 @@ class OrdersController < ApplicationController
order = Order.find(params[:id])
order.send_to_supplier!(@current_user)
redirect_to order, notice: I18n.t('orders.send_to_supplier.notice')
rescue => error
redirect_to order, alert: I18n.t('errors.general_msg', :msg => error.message)
rescue StandardError => e
redirect_to order, alert: I18n.t('errors.general_msg', msg: e.message)
end
def receive
@order = Order.find(params[:id])
unless request.post?
@order_articles = @order.order_articles.ordered_or_member.includes(:article).order('articles.order_number, articles.name')
else
if request.post?
Order.transaction do
s = update_order_amounts
@order.update_attribute(:state, 'received') if @order.state != 'received'
flash[:notice] = (s ? I18n.t('orders.receive.notice', :msg => s) : I18n.t('orders.receive.notice_none'))
flash[:notice] = (s ? I18n.t('orders.receive.notice', msg: s) : I18n.t('orders.receive.notice_none'))
end
NotifyReceivedOrderJob.perform_later(@order)
if current_user.role_orders? || current_user.role_finance?
@ -145,23 +144,25 @@ class OrdersController < ApplicationController
else
redirect_to receive_order_path(@order)
end
else
@order_articles = @order.order_articles.ordered_or_member.includes(:article).order('articles.order_number, articles.name')
end
end
def receive_on_order_article_create # See publish/subscribe design pattern in /doc.
@order_article = OrderArticle.find(params[:order_article_id])
render :layout => false
render layout: false
end
def receive_on_order_article_update # See publish/subscribe design pattern in /doc.
@order_article = OrderArticle.find(params[:order_article_id])
render :layout => false
render layout: false
end
protected
def update_order_amounts
return if not params[:order_articles]
return unless params[:order_articles]
# where to leave remainder during redistribution
rest_to = []
@ -176,35 +177,42 @@ class OrdersController < ApplicationController
# "MySQL lock timeout exceeded" errors. It's ok to do
# this article-by-article anway.
params[:order_articles].each do |oa_id, oa_params|
unless oa_params.blank?
next if oa_params.blank?
oa = OrderArticle.find(oa_id)
# update attributes; don't use update_attribute because it calls save
# which makes received_changed? not work anymore
oa.attributes = oa_params
if oa.units_received_changed?
counts[0] += 1
unless oa.units_received.blank?
if oa.units_received.present?
cunits[0] += oa.units_received * oa.article.unit_quantity
oacounts = oa.redistribute oa.units_received * oa.price.unit_quantity, rest_to
oacounts.each_with_index { |c, i| cunits[i + 1] += c; counts[i + 1] += 1 if c > 0 }
oacounts.each_with_index do |c, i|
cunits[i + 1] += c
counts[i + 1] += 1 if c > 0
end
end
end
oa.save!
end
end
return nil if counts[0] == 0
notice = []
notice << I18n.t('orders.update_order_amounts.msg1', count: counts[0], units: cunits[0])
notice << I18n.t('orders.update_order_amounts.msg2', count: counts[1], units: cunits[1]) if params[:rest_to_tolerance]
if params[:rest_to_tolerance]
notice << I18n.t('orders.update_order_amounts.msg2', count: counts[1],
units: cunits[1])
end
notice << I18n.t('orders.update_order_amounts.msg3', count: counts[2], units: cunits[2]) if params[:rest_to_stock]
if counts[3] > 0 || cunits[3] > 0
notice << I18n.t('orders.update_order_amounts.msg4', count: counts[3], units: cunits[3])
notice << I18n.t('orders.update_order_amounts.msg4', count: counts[3],
units: cunits[3])
end
notice.join(', ')
end
def remove_empty_article
params[:order][:article_ids].reject!(&:blank?) if params[:order] && params[:order][:article_ids]
params[:order][:article_ids].compact_blank! if params[:order] && params[:order][:article_ids]
end
end

View file

@ -12,10 +12,10 @@ class SessionsController < ApplicationController
user = User.authenticate(params[:nick], params[:password])
if user
user.update_attribute(:last_login, Time.now)
login_and_redirect_to_return_to user, :notice => I18n.t('sessions.logged_in')
login_and_redirect_to_return_to user, notice: I18n.t('sessions.logged_in')
else
flash.now.alert = I18n.t(FoodsoftConfig[:use_nick] ? 'sessions.login_invalid_nick' : 'sessions.login_invalid_email')
render "new"
render 'new'
end
end
@ -24,7 +24,7 @@ class SessionsController < ApplicationController
if FoodsoftConfig[:logout_redirect_url].present?
redirect_to FoodsoftConfig[:logout_redirect_url]
else
redirect_to login_url, :notice => I18n.t('sessions.logged_out')
redirect_to login_url, notice: I18n.t('sessions.logged_out')
end
end

View file

@ -7,21 +7,21 @@ class StockTakingsController < ApplicationController
def new
@stock_taking = StockTaking.new
StockArticle.undeleted.each { |a| @stock_taking.stock_changes.build(:stock_article => a) }
StockArticle.undeleted.each { |a| @stock_taking.stock_changes.build(stock_article: a) }
end
def new_on_stock_article_create # See publish/subscribe design pattern in /doc.
stock_article = StockArticle.find(params[:stock_article_id])
@stock_change = StockChange.new(:stock_article => stock_article)
@stock_change = StockChange.new(stock_article: stock_article)
render :layout => false
render layout: false
end
def create
create!(:notice => I18n.t('stock_takings.create.notice'))
create!(notice: I18n.t('stock_takings.create.notice'))
end
def update
update!(:notice => I18n.t('stock_takings.update.notice'))
update!(notice: I18n.t('stock_takings.update.notice'))
end
end

View file

@ -7,57 +7,13 @@ class StockitController < ApplicationController
def index_on_stock_article_create # See publish/subscribe design pattern in /doc.
@stock_article = StockArticle.find(params[:id])
render :layout => false
render layout: false
end
def index_on_stock_article_update # See publish/subscribe design pattern in /doc.
@stock_article = StockArticle.find(params[:id])
render :layout => false
end
# three possibilites to fill a new_stock_article form
# (1) start from blank or use params
def new
@stock_article = StockArticle.new(params[:stock_article])
render :layout => false
end
# (2) StockArticle as template
def copy
@stock_article = StockArticle.find(params[:stock_article_id]).dup
render :layout => false
end
# (3) non-stock Article as template
def derive
@stock_article = Article.find(params[:old_article_id]).becomes(StockArticle).dup
render :layout => false
end
def create
@stock_article = StockArticle.new({ quantity: 0 }.merge(params[:stock_article]))
@stock_article.save!
render :layout => false
rescue ActiveRecord::RecordInvalid
render :action => 'new', :layout => false
end
def edit
@stock_article = StockArticle.find(params[:id])
render :layout => false
end
def update
@stock_article = StockArticle.find(params[:id])
@stock_article.update!(params[:stock_article])
render :layout => false
rescue ActiveRecord::RecordInvalid
render :action => 'edit', :layout => false
render layout: false
end
def show
@ -65,24 +21,68 @@ class StockitController < ApplicationController
@stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC')
end
# three possibilites to fill a new_stock_article form
# (1) start from blank or use params
def new
@stock_article = StockArticle.new(params[:stock_article])
render layout: false
end
# (2) StockArticle as template
def copy
@stock_article = StockArticle.find(params[:stock_article_id]).dup
render layout: false
end
# (3) non-stock Article as template
def derive
@stock_article = Article.find(params[:old_article_id]).becomes(StockArticle).dup
render layout: false
end
def edit
@stock_article = StockArticle.find(params[:id])
render layout: false
end
def create
@stock_article = StockArticle.new({ quantity: 0 }.merge(params[:stock_article]))
@stock_article.save!
render layout: false
rescue ActiveRecord::RecordInvalid
render action: 'new', layout: false
end
def update
@stock_article = StockArticle.find(params[:id])
@stock_article.update!(params[:stock_article])
render layout: false
rescue ActiveRecord::RecordInvalid
render action: 'edit', layout: false
end
def show_on_stock_article_update # See publish/subscribe design pattern in /doc.
@stock_article = StockArticle.find(params[:id])
render :layout => false
render layout: false
end
def destroy
@stock_article = StockArticle.find(params[:id])
@stock_article.mark_as_deleted
render :layout => false
rescue => error
render :partial => "destroy_fail", :layout => false,
:locals => { :fail_msg => I18n.t('errors.general_msg', :msg => error.message) }
render layout: false
rescue StandardError => e
render partial: 'destroy_fail', layout: false,
locals: { fail_msg: I18n.t('errors.general_msg', msg: e.message) }
end
# TODO: Fix this!!
def articles_search
@articles = Article.not_in_stock.limit(8).where('name LIKE ?', "%#{params[:term]}%")
render :json => @articles.map(&:name)
render json: @articles.map(&:name)
end
end

View file

@ -9,7 +9,7 @@ class StylesController < ApplicationController
def foodcoop
css = FoodsoftConfig[:custom_css]
if css.blank?
render body: nil, content_type: 'text/css', status: 404
render body: nil, content_type: 'text/css', status: :not_found
else
expires_in 1.week, public: true if params[:md5].present?
render body: css, content_type: 'text/css'

View file

@ -1,5 +1,5 @@
class SuppliersController < ApplicationController
before_action :authenticate_suppliers, :except => [:index, :list]
before_action :authenticate_suppliers, except: %i[index list]
helper :deliveries
def index
@ -24,6 +24,10 @@ class SuppliersController < ApplicationController
end
end
def edit
@supplier = Supplier.find(params[:id])
end
def create
@supplier = Supplier.new(supplier_params)
@supplier.supplier_category ||= SupplierCategory.first
@ -31,21 +35,17 @@ class SuppliersController < ApplicationController
flash[:notice] = I18n.t('suppliers.create.notice')
redirect_to suppliers_path
else
render :action => 'new'
render action: 'new'
end
end
def edit
@supplier = Supplier.find(params[:id])
end
def update
@supplier = Supplier.find(params[:id])
if @supplier.update(supplier_params)
flash[:notice] = I18n.t('suppliers.update.notice')
redirect_to @supplier
else
render :action => 'edit'
render action: 'edit'
end
end
@ -54,8 +54,8 @@ class SuppliersController < ApplicationController
@supplier.mark_as_deleted
flash[:notice] = I18n.t('suppliers.destroy.notice')
redirect_to suppliers_path
rescue => e
flash[:error] = I18n.t('errors.general_msg', :msg => e.message)
rescue StandardError => e
flash[:error] = I18n.t('errors.general_msg', msg: e.message)
redirect_to @supplier
end

View file

@ -11,35 +11,33 @@ class TasksController < ApplicationController
@accepted_tasks = Task.accepted_tasks_for(current_user)
end
def new
@task = Task.new(current_user_id: current_user.id)
end
def create
@task = Task.new(current_user_id: current_user.id)
@task.created_by = current_user
@task.attributes = (task_params)
if params[:periodic]
@task.periodic_task_group = PeriodicTaskGroup.new
end
if @task.save
@task.periodic_task_group.create_tasks_for_upfront_days if params[:periodic]
redirect_to tasks_url, :notice => I18n.t('tasks.create.notice')
else
render :template => "tasks/new"
end
end
def show
@task = Task.find(params[:id])
end
def new
@task = Task.new(current_user_id: current_user.id)
end
def edit
@task = Task.find(params[:id])
@periodic = !!params[:periodic]
@task.current_user_id = current_user.id
end
def create
@task = Task.new(current_user_id: current_user.id)
@task.created_by = current_user
@task.attributes = (task_params)
@task.periodic_task_group = PeriodicTaskGroup.new if params[:periodic]
if @task.save
@task.periodic_task_group.create_tasks_for_upfront_days if params[:periodic]
redirect_to tasks_url, notice: I18n.t('tasks.create.notice')
else
render template: 'tasks/new'
end
end
def update
@task = Task.find(params[:id])
task_group = @task.periodic_task_group
@ -50,16 +48,14 @@ class TasksController < ApplicationController
if @task.errors.empty? && @task.save
task_group.update_tasks_including(@task, prev_due_date) if params[:periodic]
flash[:notice] = I18n.t('tasks.update.notice')
if was_periodic && !@task.periodic?
flash[:notice] = I18n.t('tasks.update.notice_converted')
end
flash[:notice] = I18n.t('tasks.update.notice_converted') if was_periodic && !@task.periodic?
if @task.workgroup
redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id)
else
redirect_to tasks_url
end
else
render :template => "tasks/edit"
render template: 'tasks/edit'
end
end
@ -75,7 +71,7 @@ class TasksController < ApplicationController
end
task.update_ordergroup_stats(user_ids)
redirect_to tasks_url, :notice => I18n.t('tasks.destroy.notice')
redirect_to tasks_url, notice: I18n.t('tasks.destroy.notice')
end
# assign current_user to the task and set the assignment to "accepted"
@ -85,20 +81,20 @@ class TasksController < ApplicationController
if ass = task.is_assigned?(current_user)
ass.update_attribute(:accepted, true)
else
task.assignments.create(:user => current_user, :accepted => true)
task.assignments.create(user: current_user, accepted: true)
end
redirect_to user_tasks_path, :notice => I18n.t('tasks.accept.notice')
redirect_to user_tasks_path, notice: I18n.t('tasks.accept.notice')
end
# deletes assignment between current_user and given taskcurrent_user_id: current_user.id
def reject
Task.find(params[:id]).users.delete(current_user)
redirect_to :action => "index"
redirect_to action: 'index'
end
def set_done
Task.find(params[:id]).update_attribute :done, true
redirect_to tasks_url, :notice => I18n.t('tasks.set_done.notice')
redirect_to tasks_url, notice: I18n.t('tasks.set_done.notice')
end
# Shows all tasks, which are already done
@ -109,9 +105,9 @@ class TasksController < ApplicationController
# shows workgroup (normal group) to edit weekly_tasks_template
def workgroup
@group = Group.find(params[:workgroup_id])
if @group.is_a? Ordergroup
redirect_to tasks_url, :alert => I18n.t('tasks.error_not_found')
end
return unless @group.is_a? Ordergroup
redirect_to tasks_url, alert: I18n.t('tasks.error_not_found')
end
private

View file

@ -3,7 +3,7 @@ class UsersController < ApplicationController
def index
@users = User.undeleted.natural_search(params[:q])
respond_to do |format|
format.json { render :json => @users.map(&:token_attributes).to_json }
format.json { render json: @users.map(&:token_attributes).to_json }
end
end
end

View file

@ -1,11 +1,11 @@
class OrderByArticles < OrderPdf
def filename
I18n.t('documents.order_by_articles.filename', :name => order.name, :date => order.ends.to_date) + '.pdf'
I18n.t('documents.order_by_articles.filename', name: order.name, date: order.ends.to_date) + '.pdf'
end
def title
I18n.t('documents.order_by_articles.title', :name => order.name,
:date => order.ends.strftime(I18n.t('date.formats.default')))
I18n.t('documents.order_by_articles.title', name: order.name,
date: order.ends.strftime(I18n.t('date.formats.default')))
end
def body

View file

@ -1,11 +1,11 @@
class OrderByGroups < OrderPdf
def filename
I18n.t('documents.order_by_groups.filename', :name => order.name, :date => order.ends.to_date) + '.pdf'
I18n.t('documents.order_by_groups.filename', name: order.name, date: order.ends.to_date) + '.pdf'
end
def title
I18n.t('documents.order_by_groups.title', :name => order.name,
:date => order.ends.strftime(I18n.t('date.formats.default')))
I18n.t('documents.order_by_groups.title', name: order.name,
date: order.ends.strftime(I18n.t('date.formats.default')))
end
def body

View file

@ -2,7 +2,7 @@ class OrderFax < OrderPdf
BATCH_SIZE = 250
def filename
I18n.t('documents.order_fax.filename', :name => order.name, :date => order.ends.to_date) + '.pdf'
I18n.t('documents.order_fax.filename', name: order.name, date: order.ends.to_date) + '.pdf'
end
def title
@ -20,16 +20,18 @@ class OrderFax < OrderPdf
move_down 5
text "#{contact[:zip_code]} #{contact[:city]}", size: fontsize(9), align: :right
move_down 5
unless order.supplier.try(:customer_number).blank?
text "#{Supplier.human_attribute_name :customer_number}: #{order.supplier[:customer_number]}", size: fontsize(9), align: :right
if order.supplier.try(:customer_number).present?
text "#{Supplier.human_attribute_name :customer_number}: #{order.supplier[:customer_number]}",
size: fontsize(9), align: :right
move_down 5
end
unless contact[:phone].blank?
if contact[:phone].present?
text "#{Supplier.human_attribute_name :phone}: #{contact[:phone]}", size: fontsize(9), align: :right
move_down 5
end
unless contact[:email].blank?
text "#{Supplier.human_attribute_name :email}: #{contact[:email]}", size: fontsize(9), align: :right
if contact[:email].present?
text "#{Supplier.human_attribute_name :email}: #{contact[:email]}", size: fontsize(9),
align: :right
end
end
@ -38,7 +40,7 @@ class OrderFax < OrderPdf
text order.name
move_down 5
text order.supplier.try(:address).to_s
unless order.supplier.try(:fax).blank?
if order.supplier.try(:fax).present?
move_down 5
text "#{Supplier.human_attribute_name :fax}: #{order.supplier[:fax]}"
end
@ -50,7 +52,7 @@ class OrderFax < OrderPdf
move_down 10
text "#{Delivery.human_attribute_name :date}:"
move_down 10
unless order.supplier.try(:contact_person).blank?
if order.supplier.try(:contact_person).present?
text "#{Supplier.human_attribute_name :contact_person}: #{order.supplier[:contact_person]}"
move_down 10
end
@ -78,8 +80,8 @@ class OrderFax < OrderPdf
table.row(0).border_bottom_width = 2
table.columns(1).align = :right
table.columns(3..6).align = :right
table.row(data.length - 1).columns(0..5).borders = [:top, :bottom]
table.row(data.length - 1).columns(0).borders = [:top, :bottom, :left]
table.row(data.length - 1).columns(0..5).borders = %i[top bottom]
table.row(data.length - 1).columns(0).borders = %i[top bottom left]
table.row(data.length - 1).border_top_width = 2
end
# font_size: fontsize(8),
@ -98,7 +100,7 @@ class OrderFax < OrderPdf
.preload(:article, :article_price)
end
def each_order_article
order_articles.find_each_with_order(batch_size: BATCH_SIZE) { |oa| yield oa }
def each_order_article(&block)
order_articles.find_each_with_order(batch_size: BATCH_SIZE, &block)
end
end

View file

@ -3,12 +3,12 @@ class OrderMatrix < OrderPdf
PLACEHOLDER_CHAR = 'X'
def filename
I18n.t('documents.order_matrix.filename', :name => @order.name, :date => @order.ends.to_date) + '.pdf'
I18n.t('documents.order_matrix.filename', name: @order.name, date: @order.ends.to_date) + '.pdf'
end
def title
I18n.t('documents.order_matrix.title', :name => @order.name,
:date => @order.ends.strftime(I18n.t('date.formats.default')))
I18n.t('documents.order_matrix.title', name: @order.name,
date: @order.ends.strftime(I18n.t('date.formats.default')))
end
def body
@ -87,7 +87,7 @@ class OrderMatrix < OrderPdf
table.cells.border_width = 0.5
table.cells.border_color = '666666'
table.row(0).borders = [:bottom, :left]
table.row(0).borders = %i[bottom left]
table.row(0).padding = [2, 0, 2, 0]
table.row(1..-1).height = row_height_1
table.column(0..1).borders = []
@ -106,7 +106,7 @@ class OrderMatrix < OrderPdf
table.column(2 + idx).border_width = 2
end
table.row_colors = ['dddddd', 'ffffff']
table.row_colors = %w[dddddd ffffff]
end
first_page = false

View file

@ -28,7 +28,11 @@ module Admin::ConfigsHelper
options[:default] = options[:input_html].delete(:value)
return form.input key, options, &block
end
block ||= proc { config_input_field form, key, options.merge(options[:input_html]) } if options[:as] == :select_recurring
if options[:as] == :select_recurring
block ||= proc {
config_input_field form, key, options.merge(options[:input_html])
}
end
form.input key, options, &block
end
@ -57,11 +61,12 @@ module Admin::ConfigsHelper
unchecked_value = options.delete(:unchecked_value) || 'false'
options[:checked] = 'checked' if v = options.delete(:value) && v != 'false'
# different key for hidden field so that allow clocking on label focuses the control
form.hidden_field(key, id: "#{key}_", value: unchecked_value, as: :hidden) + form.check_box(key, options, checked_value, false)
form.hidden_field(key, id: "#{key}_", value: unchecked_value,
as: :hidden) + form.check_box(key, options, checked_value, false)
elsif options[:as] == :select_recurring
options[:value] = FoodsoftDateUtil.rule_from(options[:value])
options[:rules] ||= []
options[:rules].unshift options[:value] unless options[:value].blank?
options[:rules].unshift options[:value] if options[:value].present?
options[:rules].push [I18n.t('recurring_select.not_recurring'), '{}'] if options.delete(:allow_blank) # blank after current value
form.select_recurring key, options.delete(:rules).uniq, options
else
@ -73,7 +78,7 @@ module Admin::ConfigsHelper
# @param form [ActionView::Helpers::FormBuilder] Form object.
# @param key [Symbol, String] Configuration key of a boolean (e.g. +use_messages+).
# @option options [String] :label Label to show
def config_use_heading(form, key, options = {})
def config_use_heading(form, key, options = {}, &block)
head = content_tag :label do
lbl = options[:label] || config_input_label(form, key)
field = config_input_field(form, key, as: :boolean, boolean_style: :inline,
@ -83,9 +88,7 @@ module Admin::ConfigsHelper
content_tag :span, (lbl + field).html_safe, config_input_tooltip_options(form, key, {})
end
end
fields = content_tag(:fieldset, id: "#{key}-fields", class: "collapse#{' in' if @cfg[key]}") do
yield
end
fields = content_tag(:fieldset, id: "#{key}-fields", class: "collapse#{' in' if @cfg[key]}", &block)
head + fields
end
@ -127,7 +130,7 @@ module Admin::ConfigsHelper
# tooltip with help info to the right
cfg_path = form.lookup_model_names[1..-1] + [key]
tooltip = I18n.t("config.hints.#{cfg_path.map(&:to_s).join('.')}", default: '')
unless tooltip.blank?
if tooltip.present?
options[:data] ||= {}
options[:data][:toggle] ||= 'tooltip'
options[:data][:placement] ||= 'right'

View file

@ -2,9 +2,7 @@ module Admin::OrdergroupsHelper
def ordergroup_members_title(ordergroup)
s = ''
s += ordergroup.users.map(&:name).join(', ') if ordergroup.users.any?
if ordergroup.contact_person.present?
s += "\n" + Ordergroup.human_attribute_name(:contact) + ": " + ordergroup.contact_person
end
s += "\n" + Ordergroup.human_attribute_name(:contact) + ': ' + ordergroup.contact_person if ordergroup.contact_person.present?
s
end
end

View file

@ -4,7 +4,7 @@ module ApplicationHelper
include PathHelper
def format_time(time = Time.now)
I18n.l(time, :format => "%d.%m.%Y %H:%M") unless time.nil?
I18n.l(time, format: '%d.%m.%Y %H:%M') unless time.nil?
end
def format_date(time = Time.now)
@ -16,7 +16,7 @@ module ApplicationHelper
end
def format_datetime_timespec(time, format)
I18n.l(time, :format => format) unless (time.nil? || format.nil?)
I18n.l(time, format: format) unless time.nil? || format.nil?
end
def format_currency(amount)
@ -26,28 +26,28 @@ module ApplicationHelper
# Splits an IBAN into groups of 4 digits displayed with margins in between
def format_iban(iban)
iban && iban.scan(/..?.?.?/).map { |item| content_tag(:span, item, style: "margin-right: 0.5em;") }.join.html_safe
iban && iban.scan(/..?.?.?/).map { |item| content_tag(:span, item, style: 'margin-right: 0.5em;') }.join.html_safe
end
# Creates ajax-controlled-links for pagination
def pagination_links_remote(collection, options = {})
per_page = options[:per_page] || @per_page
params = options[:params] || {}
params = params.merge({ :per_page => per_page })
paginate collection, :params => params, :remote => true
params = params.merge({ per_page: per_page })
paginate collection, params: params, remote: true
end
# Link-collection for per_page-options when using the pagination-plugin
def items_per_page(options = {})
per_page_options = options[:per_page_options] || [20, 50, 100, 500]
current = options[:current] || @per_page
params = params || {}
params ||= {}
links = per_page_options.map do |per_page|
params.merge!({ :per_page => per_page })
params.merge!({ per_page: per_page })
link_class = 'btn'
link_class << ' disabled' if per_page == current
link_to(per_page, params, :remote => true, class: link_class)
link_to(per_page, params, remote: true, class: link_class)
end
if options[:wrap] == false
@ -63,21 +63,19 @@ module ApplicationHelper
# Hmtl options
remote = options[:remote].nil? ? true : options[:remote]
class_name = case params[:sort]
when key then
when key
'sortup'
when key + '_reverse' then
when key + '_reverse'
'sortdown'
else
nil
end
html_options = {
:title => I18n.t('helpers.application.sort_by', text: text),
:remote => remote,
:class => class_name
title: I18n.t('helpers.application.sort_by', text: text),
remote: remote,
class: class_name
}
# Url options
key += "_reverse" if params[:sort] == key
key += '_reverse' if params[:sort] == key
per_page = options[:per_page] || @per_page
url_options = params.merge(per_page: per_page, sort: key)
url_options.merge!({ page: params[:page] }) if params[:page]
@ -95,14 +93,16 @@ module ApplicationHelper
# be overridden by the option 'desc'.
# Other options are passed through to I18n.
def heading_helper(model, attribute, options = {})
i18nopts = { count: 2 }.merge(options.select { |a| !['short', 'desc'].include?(a) })
i18nopts = { count: 2 }.merge(options.select { |a| !%w[short desc].include?(a) })
s = model.human_attribute_name(attribute, i18nopts)
if options[:short]
desc = options[:desc]
desc ||= model.human_attribute_name("#{attribute}_desc".to_sym, options.merge({ fallback: true, default: '', count: 2 }))
desc ||= model.human_attribute_name("#{attribute}_desc".to_sym,
options.merge({ fallback: true, default: '', count: 2 }))
desc.blank? && desc = s
sshort = model.human_attribute_name("#{attribute}_short".to_sym, options.merge({ fallback: true, default: '', count: 2 }))
s = raw "<abbr title='#{desc}'>#{sshort}</abbr>" unless sshort.blank?
sshort = model.human_attribute_name("#{attribute}_short".to_sym,
options.merge({ fallback: true, default: '', count: 2 }))
s = raw "<abbr title='#{desc}'>#{sshort}</abbr>" if sshort.present?
end
s
end
@ -117,7 +117,7 @@ module ApplicationHelper
# Returns the weekday. 0 is sunday, 1 is monday and so on
def weekday(dayNumber)
weekdays = I18n.t('date.day_names')
return weekdays[dayNumber]
weekdays[dayNumber]
end
# to set a title for both the h1-tag and the title in the header
@ -136,13 +136,13 @@ module ApplicationHelper
def icon(name, options = {})
icons = {
:delete => { :file => 'b_drop.png', :alt => I18n.t('ui.delete') },
:edit => { :file => 'b_edit.png', :alt => I18n.t('ui.edit') },
:members => { :file => 'b_users.png', :alt => I18n.t('helpers.application.edit_user') }
delete: { file: 'b_drop.png', alt: I18n.t('ui.delete') },
edit: { file: 'b_edit.png', alt: I18n.t('ui.edit') },
members: { file: 'b_users.png', alt: I18n.t('helpers.application.edit_user') }
}
options[:alt] ||= icons[name][:alt]
options[:title] ||= icons[name][:title]
options.merge!({ :size => '16x16', :border => "0" })
options.merge!({ size: '16x16', border: '0' })
image_tag icons[name][:file], options
end
@ -150,27 +150,29 @@ module ApplicationHelper
# Remote links with default 'loader'.gif during request
def remote_link_to(text, options = {})
remote_options = {
:before => "Element.show('loader')",
:success => "Element.hide('loader')",
:method => :get
before: "Element.show('loader')",
success: "Element.hide('loader')",
method: :get
}
link_to(text, options[:url], remote_options.merge(options))
end
def format_roles(record, icon = false)
roles = %w(suppliers article_meta orders pickups finance invoices admin)
roles = %w[suppliers article_meta orders pickups finance invoices admin]
roles.select! { |role| record.send "role_#{role}?" }
names = Hash[roles.map { |r| [r, I18n.t("helpers.application.role_#{r}")] }]
names = roles.index_with { |r| I18n.t("helpers.application.role_#{r}") }
if icon
roles.map { |r| image_tag("role-#{r}.png", size: '22x22', border: 0, alt: names[r], title: names[r]) }.join('&nbsp;').html_safe
roles.map do |r|
image_tag("role-#{r}.png", size: '22x22', border: 0, alt: names[r], title: names[r])
end.join('&nbsp;').html_safe
else
roles.map { |r| names[r] }.join(', ')
end
end
def link_to_gmaps(address)
link_to h(address), "http://maps.google.com/?q=#{h(address)}", :title => I18n.t('helpers.application.show_google_maps'),
:target => "_blank"
link_to h(address), "http://maps.google.com/?q=#{h(address)}", title: I18n.t('helpers.application.show_google_maps'),
target: '_blank', rel: 'noopener'
end
# Returns flash messages html.
@ -186,8 +188,8 @@ module ApplicationHelper
type = :success if type == 'notice'
type = :error if type == 'alert'
text = content_tag(:div,
content_tag(:button, I18n.t('ui.marks.close').html_safe, :class => "close", "data-dismiss" => "alert") +
message, :class => "alert fade in alert-#{type}")
content_tag(:button, I18n.t('ui.marks.close').html_safe, :class => 'close', 'data-dismiss' => 'alert') +
message, class: "alert fade in alert-#{type}")
flash_messages << text if message
end
flash_messages.join("\n").html_safe
@ -195,17 +197,17 @@ module ApplicationHelper
# render base errors in a form after failed validation
# http://railsapps.github.io/twitter-bootstrap-rails.html
def base_errors resource
def base_errors(resource)
return '' if resource.errors.empty? || resource.errors[:base].empty?
messages = resource.errors[:base].map { |msg| content_tag(:li, msg) }.join
render :partial => 'shared/base_errors', :locals => { :error_messages => messages }
render partial: 'shared/base_errors', locals: { error_messages: messages }
end
# show a user, depending on settings
def show_user(user = @current_user, options = {})
if user.nil?
"?"
'?'
elsif FoodsoftConfig[:use_nick]
if options[:full] && options[:markup]
raw "<b>#{h user.nick}</b> (#{h user.first_name} #{h user.last_name})"
@ -216,7 +218,7 @@ module ApplicationHelper
user.nick.nil? ? I18n.t('helpers.application.nick_fallback') : user.nick
end
else
"#{user.first_name} #{user.last_name}" + (options[:unique] ? " (\##{user.id})" : '')
"#{user.first_name} #{user.last_name}" + (options[:unique] ? " (##{user.id})" : '')
end
end
@ -258,9 +260,9 @@ module ApplicationHelper
# @return [String] stylesheet tag for foodcoop CSS style (+custom_css+ foodcoop config)
# @see #foodcoop_css_path
def foodcoop_css_tag(options = {})
unless FoodsoftConfig[:custom_css].blank?
def foodcoop_css_tag(_options = {})
return if FoodsoftConfig[:custom_css].blank?
stylesheet_link_tag foodcoop_css_path, media: 'all'
end
end
end

View file

@ -3,13 +3,13 @@ module ArticlesHelper
def highlight_new(unequal_attributes, attribute)
return unless unequal_attributes
unequal_attributes.has_key?(attribute) ? "background-color: yellow" : ""
unequal_attributes.has_key?(attribute) ? 'background-color: yellow' : ''
end
def row_classes(article)
classes = []
classes << "unavailable" if !article.availability
classes << "just-updated" if article.recently_updated && article.availability
classes.join(" ")
classes << 'unavailable' unless article.availability
classes << 'just-updated' if article.recently_updated && article.availability
classes.join(' ')
end
end

View file

@ -11,11 +11,11 @@ module DeliveriesHelper
def articles_for_select2(articles, except = [], &block)
articles = articles.reorder('articles.name ASC')
articles = articles.reject { |a| not except.index(a.id).nil? } if except
block_given? or block = Proc.new { |a| "#{a.name} (#{number_to_currency a.price}/#{a.unit})" }
articles = articles.reject { |a| !except.index(a.id).nil? } if except
block_given? or block = proc { |a| "#{a.name} (#{number_to_currency a.price}/#{a.unit})" }
articles.map do |a|
{ :id => a.id, :text => block.call(a) }
end.unshift({ :id => '', :text => '' })
{ id: a.id, text: block.call(a) }
end.unshift({ id: '', text: '' })
end
def articles_for_table(articles)
@ -23,10 +23,14 @@ module DeliveriesHelper
end
def stock_change_remove_link(stock_change_form)
return link_to t('deliveries.stock_change_fields.remove_article'), "#", :class => 'remove_new_stock_change btn btn-small' if stock_change_form.object.new_record?
if stock_change_form.object.new_record?
return link_to t('deliveries.stock_change_fields.remove_article'), '#',
class: 'remove_new_stock_change btn btn-small'
end
output = stock_change_form.hidden_field :_destroy
output += link_to t('deliveries.stock_change_fields.remove_article'), "#", :class => 'destroy_stock_change btn btn-small'
return output.html_safe
output += link_to t('deliveries.stock_change_fields.remove_article'), '#',
class: 'destroy_stock_change btn btn-small'
output.html_safe
end
end

View file

@ -2,11 +2,11 @@ module Finance::BalancingHelper
def balancing_view_partial
view = params[:view] || 'edit_results'
case view
when 'edit_results' then
when 'edit_results'
'edit_results_by_articles'
when 'groups_overview' then
when 'groups_overview'
'shared/articles_by/groups'
when 'articles_overview' then
when 'articles_overview'
'shared/articles_by/articles'
end
end

View file

@ -1,9 +1,9 @@
module Finance::InvoicesHelper
def format_delivery_item delivery
def format_delivery_item(delivery)
format_date(delivery.date)
end
def format_order_item order
def format_order_item(order)
"#{format_date(order.ends)} (#{number_to_currency(order.sum)})"
end
end

View file

@ -2,12 +2,12 @@ module GroupOrderArticlesHelper
# return an edit field for a GroupOrderArticle result
def group_order_article_edit_result(goa)
result = number_with_precision goa.result, strip_insignificant_zeros: true
unless goa.group_order.order.finished? && current_user.role_finance?
result
else
if goa.group_order.order.finished? && current_user.role_finance?
simple_form_for goa, remote: true, html: { 'data-submit-onchange' => 'changed', class: 'delta-input' } do |f|
f.input_field :result, as: :delta, class: 'input-nano', data: { min: 0 }, id: "r_#{goa.id}", value: result
end
else
result
end
end
end

View file

@ -1,10 +1,11 @@
module GroupOrdersHelper
def data_to_js(ordering_data)
ordering_data[:order_articles].map { |id, data|
[id, data[:price], data[:unit], data[:total_price], data[:others_quantity], data[:others_tolerance], data[:used_quantity], data[:quantity_available]]
}.map { |row|
ordering_data[:order_articles].map do |id, data|
[id, data[:price], data[:unit], data[:total_price], data[:others_quantity], data[:others_tolerance],
data[:used_quantity], data[:quantity_available]]
end.map do |row|
"addData(#{row.join(', ')});"
}.join("\n")
end.join("\n")
end
# Returns a link to the page where a group_order can be edited.
@ -14,9 +15,9 @@ module GroupOrdersHelper
path = if options[:show] && group_order
group_order_path(group_order)
elsif group_order
edit_group_order_path(group_order, :order_id => order.id)
edit_group_order_path(group_order, order_id: order.id)
else
new_group_order_path(:order_id => order.id)
new_group_order_path(order_id: order.id)
end
options.delete(:show)
name = block_given? ? capture(&block) : order.name
@ -26,7 +27,7 @@ module GroupOrdersHelper
# Return css class names for order result table
def order_article_class_name(quantity, tolerance, result)
if (quantity + tolerance > 0)
if quantity + tolerance > 0
result > 0 ? 'success' : 'failed'
else
'ignored'
@ -45,12 +46,12 @@ module GroupOrdersHelper
end
def get_missing_units_css_class(quantity_missing)
if (quantity_missing == 1)
return 'missing-few';
elsif (quantity_missing == 0)
return ''
if quantity_missing == 1
'missing-few'
elsif quantity_missing == 0
''
else
return 'missing-many'
'missing-many'
end
end
end

View file

@ -1,6 +1,6 @@
module OrderArticlesHelper
def article_label_with_unit(article)
pkg_info = pkg_helper(article, plain: true)
"#{article.name} (#{[article.unit, pkg_info].reject(&:blank?).join(' ')})"
"#{article.name} (#{[article.unit, pkg_info].compact_blank.join(' ')})"
end
end

View file

@ -18,7 +18,7 @@ module OrdersHelper
def options_for_suppliers_to_select
options = [[I18n.t('helpers.orders.option_choose')]]
options += Supplier.map { |s| [s.name, url_for(action: "new", supplier_id: s.id)] }
options += Supplier.map { |s| [s.name, url_for(action: 'new', supplier_id: s.id)] }
options += [[I18n.t('helpers.orders.option_stock'), url_for(action: 'new', supplier_id: nil)]]
options_for_select(options)
end
@ -29,14 +29,14 @@ module OrdersHelper
nil
else
units_info = []
[:units_to_order, :units_billed, :units_received].map do |unit|
if n = order_article.send(unit)
%i[units_to_order units_billed units_received].map do |unit|
next unless n = order_article.send(unit)
line = n.to_s + ' '
line += pkg_helper(order_article.price, options) + ' ' unless n == 0
line += OrderArticle.human_attribute_name("#{unit}_short", count: n)
units_info << line
end
end
units_info.join(', ').html_safe
end
end
@ -67,8 +67,8 @@ module OrdersHelper
def pkg_helper_icon(c = nil, options = {})
options = { tag: 'i', class: '' }.merge(options)
if c.nil?
c = "&nbsp;".html_safe
options[:class] += " icon-only"
c = '&nbsp;'.html_safe
options[:class] += ' icon-only'
end
content_tag(options[:tag], c, class: "package #{options[:class]}").html_safe
end
@ -94,11 +94,12 @@ module OrdersHelper
autocomplete: 'off'
if order_article.result_manually_changed?
input_html = content_tag(:span, class: 'input-prepend intable', title: t('orders.edit_amount.field_locked_title', default: '')) {
input_html = content_tag(:span, class: 'input-prepend intable',
title: t('orders.edit_amount.field_locked_title', default: '')) do
button_tag(nil, type: :button, class: 'btn unlocker') {
content_tag(:i, nil, class: 'icon icon-unlock')
} + input_html
}
end
end
input_html.html_safe
@ -109,18 +110,16 @@ module OrdersHelper
def ordergroup_count(order)
group_orders = order.group_orders.includes(:ordergroup)
txt = "#{group_orders.count} #{Ordergroup.model_name.human count: group_orders.count}"
if group_orders.count == 0
return txt
else
return txt if group_orders.count == 0
desc = group_orders.includes(:ordergroup).map { |g| g.ordergroup_name }.join(', ')
content_tag(:abbr, txt, title: desc).html_safe
end
end
# @param order_or_supplier [Order, Supplier] Order or supplier to link to
# @return [String] Link to order or supplier, showing its name.
def supplier_link(order_or_supplier)
if order_or_supplier.kind_of?(Order) && order_or_supplier.stockit?
if order_or_supplier.is_a?(Order) && order_or_supplier.stockit?
link_to(order_or_supplier.name, stock_articles_path).html_safe
else
link_to(@order.supplier.name, supplier_path(@order.supplier)).html_safe
@ -152,7 +151,8 @@ module OrdersHelper
if order.stockit?
content_tag :div, t('orders.index.action_receive'), class: "btn disabled #{options[:class]}"
else
link_to t('orders.index.action_receive'), receive_order_path(order), class: "btn#{' btn-success' unless order.received?} #{options[:class]}"
link_to t('orders.index.action_receive'), receive_order_path(order),
class: "btn#{' btn-success' unless order.received?} #{options[:class]}"
end
end
end

View file

@ -1,8 +1,8 @@
module StockitHelper
def stock_article_classes(article)
class_names = []
class_names << "unavailable" if article.quantity_available <= 0
class_names.join(" ")
class_names << 'unavailable' if article.quantity_available <= 0
class_names.join(' ')
end
def link_to_stock_change_reason(stock_change)
@ -17,8 +17,8 @@ module StockitHelper
def stock_article_price_hint(stock_article)
t('simple_form.hints.stock_article.edit_stock_article.price',
:stock_article_copy_link => link_to(t('stockit.form.copy_stock_article'),
stock_article_copy_link: link_to(t('stockit.form.copy_stock_article'),
stock_article_copy_path(stock_article),
:remote => true))
remote: true))
end
end

View file

@ -1,16 +1,16 @@
module TasksHelper
def task_assignments(task)
task.assignments.map do |ass|
content_tag :span, show_user(ass.user), :class => (ass.accepted? ? 'accepted' : 'unaccepted')
end.join(", ").html_safe
content_tag :span, show_user(ass.user), class: (ass.accepted? ? 'accepted' : 'unaccepted')
end.join(', ').html_safe
end
# generate colored number of still required users
def highlighted_required_users(task)
unless task.enough_users_assigned?
return if task.enough_users_assigned?
content_tag :span, task.still_required_users, class: 'badge badge-important',
title: I18n.t('helpers.tasks.required_users', :count => task.still_required_users)
end
title: I18n.t('helpers.tasks.required_users', count: task.still_required_users)
end
def task_title(task)

View file

@ -6,7 +6,7 @@ class DeltaInput < SimpleForm::Inputs::StringInput
options[:data] ||= {}
options[:data][:delta] ||= 1
options[:autocomplete] ||= 'off'
# TODO get generated id, don't know how yet - `add_default_name_and_id_for_value` might be an option
# TODO: get generated id, don't know how yet - `add_default_name_and_id_for_value` might be an option
template.content_tag :div, class: 'delta-input input-prepend input-append' do
delta_button(content_tag(:i, nil, class: 'icon icon-minus'), -1, options) +

View file

@ -29,7 +29,7 @@ class AppleBar
def mean_order_amount_per_job
(1 / @global_avg).round
rescue
rescue StandardError
0
end

View file

@ -41,14 +41,14 @@ class BankAccountConnector
end
end
@@registered_classes = Set.new
@registered_classes = Set.new
def self.register(klass)
@@registered_classes.add klass
@registered_classes.add klass
end
def self.find(iban)
@@registered_classes.each do |klass|
@registered_classes.each do |klass|
return klass if klass.handles(iban)
end
nil

View file

@ -17,16 +17,16 @@ class BankAccountInformationImporter
ret = 0
booked.each do |t|
amount = parse_account_information_amount t[:transactionAmount]
entityName = amount < 0 ? t[:creditorName] : t[:debtorName]
entityAccount = amount < 0 ? t[:creditorAccount] : t[:debtorAccount]
entity_name = amount < 0 ? t[:creditorName] : t[:debtorName]
entity_account = amount < 0 ? t[:creditorAccount] : t[:debtorAccount]
reference = [t[:endToEndId], t[:remittanceInformationUnstructured]].join("\n").strip
@bank_account.bank_transactions.where(external_id: t[:transactionId]).first_or_create.update({
date: t[:bookingDate],
amount: amount,
iban: entityAccount && entityAccount[:iban],
iban: entity_account && entity_account[:iban],
reference: reference,
text: entityName,
text: entity_name,
receipt: t[:additionalInformation]
})
ret += 1
@ -34,7 +34,7 @@ class BankAccountInformationImporter
balances = (data[:balances] ? data[:balances].map { |b| [b[:balanceType], b[:balanceAmount]] } : []).to_h
balance = balances.values.first
%w(closingBooked expected authorised openingBooked interimAvailable forwardAvailable nonInvoiced).each do |type|
%w[closingBooked expected authorised openingBooked interimAvailable forwardAvailable nonInvoiced].each do |type|
value = balances[type]
if value
balance = value

View file

@ -10,66 +10,68 @@ module DateTimeAttributeValidate
super
attributes.each do |attribute|
validate -> { self.send("#{attribute}_datetime_value_valid") }
validate -> { send("#{attribute}_datetime_value_valid") }
# allow resetting the field to nil
before_validation do
if self.instance_variable_get("@#{attribute}_is_set")
date = self.instance_variable_get("@#{attribute}_date_value")
time = self.instance_variable_get("@#{attribute}_time_value")
if date.blank? && time.blank?
self.send("#{attribute}=", nil)
end
if instance_variable_get("@#{attribute}_is_set")
date = instance_variable_get("@#{attribute}_date_value")
time = instance_variable_get("@#{attribute}_time_value")
send("#{attribute}=", nil) if date.blank? && time.blank?
end
end
# remember old date and time values
define_method("#{attribute}_date_value=") do |val|
self.instance_variable_set("@#{attribute}_is_set", true)
self.instance_variable_set("@#{attribute}_date_value", val)
instance_variable_set("@#{attribute}_is_set", true)
instance_variable_set("@#{attribute}_date_value", val)
begin
self.send("#{attribute}_date=", val)
rescue
send("#{attribute}_date=", val)
rescue StandardError
nil
end
end
define_method("#{attribute}_time_value=") do |val|
self.instance_variable_set("@#{attribute}_is_set", true)
self.instance_variable_set("@#{attribute}_time_value", val)
instance_variable_set("@#{attribute}_is_set", true)
instance_variable_set("@#{attribute}_time_value", val)
begin
self.send("#{attribute}_time=", val)
rescue
send("#{attribute}_time=", val)
rescue StandardError
nil
end
end
# fallback to field when values are not set
define_method("#{attribute}_date_value") do
self.instance_variable_get("@#{attribute}_date_value") || self.send("#{attribute}_date").try { |e| e.strftime('%Y-%m-%d') }
instance_variable_get("@#{attribute}_date_value") || send("#{attribute}_date").try do |e|
e.strftime('%Y-%m-%d')
end
end
define_method("#{attribute}_time_value") do
self.instance_variable_get("@#{attribute}_time_value") || self.send("#{attribute}_time").try { |e| e.strftime('%H:%M') }
instance_variable_get("@#{attribute}_time_value") || send("#{attribute}_time").try do |e|
e.strftime('%H:%M')
end
end
private
# validate date and time
define_method("#{attribute}_datetime_value_valid") do
date = self.instance_variable_get("@#{attribute}_date_value")
date = instance_variable_get("@#{attribute}_date_value")
unless date.blank? || begin
Date.parse(date)
rescue
rescue StandardError
nil
end
errors.add(attribute, "is not a valid date") # @todo I18n
errors.add(attribute, 'is not a valid date') # @todo I18n
end
time = self.instance_variable_get("@#{attribute}_time_value")
time = instance_variable_get("@#{attribute}_time_value")
unless time.blank? || begin
Time.parse(time)
rescue
rescue StandardError
nil
end
errors.add(attribute, "is not a valid time") # @todo I18n
errors.add(attribute, 'is not a valid time') # @todo I18n
end
end
end

View file

@ -14,7 +14,7 @@ module Foodsoft
cattr_accessor :variables
# Hash of variables. Note that keys are Strings.
@@variables = {
@variables = {
'scope' => -> { FoodsoftConfig.scope },
'name' => -> { FoodsoftConfig[:name] },
'contact.street' => -> { FoodsoftConfig[:contact][:street] },
@ -39,13 +39,13 @@ module Foodsoft
'supplier_count' => -> { Supplier.undeleted.count },
'active_supplier_count' => -> { active_supplier_count },
'active_suppliers' => -> { active_suppliers },
'first_order_date' => -> { I18n.l Order.first.try { |o| o.starts.to_date } }
'first_order_date' => -> { I18n.l(Order.first.try { |o| o.starts.to_date }) }
}
# Return expanded variable
# @return [String] Expanded variable
def self.get(var)
s = @@variables[var.to_s]
s = @variables[var.to_s]
s.respond_to?(:call) ? s.call : s.to_s
end
@ -55,7 +55,7 @@ module Foodsoft
# @return [String] Expanded string
def self.expand(str, options = {})
str.gsub(/{{([._a-zA-Z0-9]+)}}/) do
options[::Regexp.last_match(1)] || self.get(::Regexp.last_match(1))
options[::Regexp.last_match(1)] || get(::Regexp.last_match(1))
end
end

View file

@ -70,7 +70,7 @@ class FoodsoftConfig
# Load initial config from development or production
set_config Rails.env
# Overwrite scope to have a better namescope than 'production'
self.scope = config[:default_scope] or raise "No default_scope is set"
self.scope = config[:default_scope] or raise 'No default_scope is set'
# Set defaults for backward-compatibility
set_missing
# Make sure relevant configuration is applied, also in single coops mode,
@ -79,7 +79,7 @@ class FoodsoftConfig
end
def init_mailing
[:protocol, :host, :port, :script_name].each do |k|
%i[protocol host port script_name].each do |k|
ActionMailer::Base.default_url_options[k] = self[k] if self[k]
end
end
@ -117,7 +117,7 @@ class FoodsoftConfig
# @return [Object] Value of the key.
def [](key)
if RailsSettings::CachedSettings.table_exists? && allowed_key?(key)
value = RailsSettings::CachedSettings["foodcoop.#{self.scope}.#{key}"]
value = RailsSettings::CachedSettings["foodcoop.#{scope}.#{key}"]
value = config[key] if value.nil?
value
else
@ -139,20 +139,20 @@ class FoodsoftConfig
if config[key] == value || (config[key].nil? && value == false)
# delete (ok if it was already deleted)
begin
RailsSettings::CachedSettings.destroy "foodcoop.#{self.scope}.#{key}"
RailsSettings::CachedSettings.destroy "foodcoop.#{scope}.#{key}"
rescue RailsSettings::Settings::SettingNotFound
end
else
# or store
RailsSettings::CachedSettings["foodcoop.#{self.scope}.#{key}"] = value
RailsSettings::CachedSettings["foodcoop.#{scope}.#{key}"] = value
end
true
end
# @return [Array<String>] Configuration keys that are set (either in +app_config.yml+ or database).
def keys
keys = RailsSettings::CachedSettings.get_all("foodcoop.#{self.scope}.").try(:keys) || []
keys.map! { |k| k.gsub(/^foodcoop\.#{self.scope}\./, '') }
keys = RailsSettings::CachedSettings.get_all("foodcoop.#{scope}.").try(:keys) || []
keys.map! { |k| k.gsub(/^foodcoop\.#{scope}\./, '') }
keys += config.keys
keys.map(&:to_s).uniq
end
@ -181,10 +181,10 @@ class FoodsoftConfig
# @return [Boolean] Whether this key may be set in the database
def allowed_key?(key)
# fast check for keys without nesting
if self.config[:protected].include? key
!self.config[:protected][key]
if config[:protected].include? key
!config[:protected][key]
else
!self.config[:protected][:all]
!config[:protected][:all]
end
# @todo allow to check nested keys as well
end
@ -287,7 +287,9 @@ class FoodsoftConfig
def normalize_value(value)
value = value.map { |v| normalize_value(v) } if value.is_a? Array
if value.is_a? Hash
value = ActiveSupport::HashWithIndifferentAccess[value.to_a.map { |a| [a[0], normalize_value(a[1])] }]
value = ActiveSupport::HashWithIndifferentAccess[value.to_a.map do |a|
[a[0], normalize_value(a[1])]
end]
end
case value
when 'true' then true

View file

@ -8,26 +8,24 @@ module FoodsoftDateUtil
# @todo handle ical parse errors
occ = begin
schedule.next_occurrence(from).to_time
rescue
rescue StandardError
nil
end
end
if options && options[:time] && occ
occ = occ.beginning_of_day.advance(seconds: Time.parse(options[:time]).seconds_since_midnight)
end
occ = occ.beginning_of_day.advance(seconds: Time.parse(options[:time]).seconds_since_midnight) if options && options[:time] && occ
occ
end
# @param p [String, Symbol, Hash, IceCube::Rule] What to return a rule from.
# @param rule [String, Symbol, Hash, IceCube::Rule] What to return a rule from.
# @return [IceCube::Rule] Recurring rule
def self.rule_from(p)
case p
def self.rule_from(rule)
case rule
when String
IceCube::Rule.from_ical(p)
IceCube::Rule.from_ical(rule)
when Hash
IceCube::Rule.from_hash(p)
IceCube::Rule.from_hash(rule)
else
p
rule
end
end
end

View file

@ -7,17 +7,17 @@ class FoodsoftFile
SpreadsheetFile.parse file, options do |row, row_index|
next if row[2].blank?
article = { :order_number => row[1],
:name => row[2],
:note => row[3],
:manufacturer => row[4],
:origin => row[5],
:unit => row[6],
:price => row[7],
:tax => row[8],
:deposit => (row[9].nil? ? "0" : row[9]),
:unit_quantity => row[10],
:article_category => row[13] }
article = { order_number: row[1],
name: row[2],
note: row[3],
manufacturer: row[4],
origin: row[5],
unit: row[6],
price: row[7],
tax: row[8],
deposit: (row[9].nil? ? '0' : row[9]),
unit_quantity: row[10],
article_category: row[13] }
status = row[0] && row[0].strip.downcase == 'x' ? :outlisted : nil
yield status, article, row_index
end

View file

@ -23,8 +23,8 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
recipient = rcpt_to.gsub(/^\s*<\s*(.*)\s*>\s*$/, '\1')
@handlers << self.class.find_handler(recipient)
rcpt_to
rescue => error
logger.info("Can not accept mail for '#{rcpt_to}': #{error}")
rescue StandardError => e
logger.info("Can not accept mail for '#{rcpt_to}': #{e}")
raise MidiSmtpServer::Smtpd550Exception
end
@ -32,16 +32,16 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
@handlers.each do |handler|
handler.call(ctx[:message][:data])
end
rescue => error
ExceptionNotifier.notify_exception(error, data: ctx)
raise error
rescue StandardError => e
ExceptionNotifier.notify_exception(e, data: ctx)
raise e
ensure
@handlers.clear
end
def self.find_handler(recipient)
m = /(?<foodcoop>[^@.]+)\.(?<address>[^@]+)(@(?<hostname>[^@]+))?/.match recipient
raise "recipient is missing or has an invalid format" if m.nil?
raise 'recipient is missing or has an invalid format' if m.nil?
raise "Foodcoop '#{m[:foodcoop]}' could not be found" unless FoodsoftConfig.allowed_foodcoop? m[:foodcoop]
FoodsoftConfig.select_multifoodcoop m[:foodcoop]
@ -53,6 +53,6 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
end
end
raise "invalid format for recipient"
raise 'invalid format for recipient'
end
end

View file

@ -14,7 +14,7 @@ class OrderCsv < RenderCsv
end
def data
@object.order_articles.ordered.includes([:article, :article_price]).all.map do |oa|
@object.order_articles.ordered.includes(%i[article article_price]).all.map do |oa|
yield [
oa.units_to_order,
oa.article.order_number,

View file

@ -55,7 +55,7 @@ class OrderPdf < RenderPdf
end
def group_order_article_quantity_with_tolerance(goa)
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : "#{goa.quantity}"
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity.to_s
end
def group_order_article_result(goa)
@ -88,7 +88,7 @@ class OrderPdf < RenderPdf
.pluck('groups.name', 'SUM(group_orders.price)', 'ordergroup_id', 'SUM(group_orders.transport)')
result.map do |item|
[item.first || stock_ordergroup_name] + item[1..-1]
[item.first || stock_ordergroup_name] + item[1..]
end
end
@ -103,7 +103,7 @@ class OrderPdf < RenderPdf
def each_ordergroup_batch(batch_size)
offset = 0
while true
loop do
go_records = ordergroups(offset, batch_size)
break unless go_records.any?
@ -136,7 +136,7 @@ class OrderPdf < RenderPdf
group_order_articles(ordergroup)
.includes(order_article: { article: [:supplier] })
.order('suppliers.name, articles.name')
.preload(order_article: [:article_price, :order])
.preload(order_article: %i[article_price order])
.each(&block)
end

View file

@ -8,23 +8,19 @@ class OrderTxt
def to_txt
supplier = @order.supplier
contact = FoodsoftConfig[:contact].symbolize_keys
text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name])
text += "\n#{Supplier.human_attribute_name(:customer_number)}: #{supplier.customer_number}" unless supplier.customer_number.blank?
text = I18n.t('orders.fax.heading', name: FoodsoftConfig[:name])
text += "\n#{Supplier.human_attribute_name(:customer_number)}: #{supplier.customer_number}" if supplier.customer_number.present?
text += "\n" + I18n.t('orders.fax.delivery_day')
text += "\n\n#{supplier.name}\n#{supplier.address}\n#{Supplier.human_attribute_name(:fax)}: #{supplier.fax}\n\n"
text += "****** " + I18n.t('orders.fax.to_address') + "\n\n"
text += '****** ' + I18n.t('orders.fax.to_address') + "\n\n"
text += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n"
text += "****** " + I18n.t('orders.fax.articles') + "\n\n"
text += format("%8s %8s %s\n", I18n.t('orders.fax.number'), I18n.t('orders.fax.amount'), I18n.t('orders.fax.name'))
text += '****** ' + I18n.t('orders.fax.articles') + "\n\n"
text += format("%8s %8s %s\n", I18n.t('orders.fax.number'), I18n.t('orders.fax.amount'),
I18n.t('orders.fax.name'))
# now display all ordered articles
@order.order_articles.ordered.includes([:article, :article_price]).each do |oa|
@order.order_articles.ordered.includes(%i[article article_price]).each do |oa|
text += format("%8s %8d %s\n", oa.article.order_number, oa.units_to_order.to_i, oa.article.name)
end
text
end
# Helper method to test pdf via rails console: OrderTxt.new(order).save_tmp
def save_tmp
File.write("#{Rails.root}/tmp/#{self.class.to_s.underscore}.txt", to_csv.force_encoding("UTF-8"))
end
end

View file

@ -13,7 +13,7 @@ class RenderCsv
end
def to_csv
options = @options.select { |k| %w(col_sep row_sep).include? k.to_s }
options = @options.select { |k| %w[col_sep row_sep].include? k.to_s }
ret = CSV.generate options do |csv|
if h = header
csv << h
@ -31,12 +31,6 @@ class RenderCsv
yield []
end
# Helper method to test pdf via rails console: OrderCsv.new(order).save_tmp
def save_tmp
encoding = @options[:encoding] || 'UTF-8'
File.write("#{Rails.root}/tmp/#{self.class.to_s.underscore}.csv", to_csv.force_encoding(encoding))
end
# XXX disable unit to avoid encoding problems, both in unit and whitespace. Also allows computations in spreadsheet.
def number_to_currency(number, options = {})
super(number, options.merge({ unit: '' }))

View file

@ -28,9 +28,9 @@ class RotatedCell < Prawn::Table::Cell::Text
with_font { (@pdf.width_of(@content, options) + padding_top + padding_bottom) * tan_rotation }
end
def draw_borders(pt)
def draw_borders(point)
@pdf.mask(:line_width, :stroke_color) do
x, y = pt
x, y = point
from = [[x - skew, y + (border_top_width / 2.0)],
to = [x, y - height - (border_bottom_width / 2.0)]]
@ -118,11 +118,6 @@ class RenderPdf < Prawn::Document
render # Render pdf
end
# Helper method to test pdf via rails console: OrderByGroups.new(order).save_tmp
def save_tmp
File.write("#{Rails.root}/tmp/#{self.class.to_s.underscore}.pdf", to_pdf.force_encoding("UTF-8"))
end
# @todo avoid underscore instead of unicode whitespace in pdf :/
def number_to_currency(number, options = {})
super(number, options).gsub("\u202f", ' ') if number
@ -148,8 +143,8 @@ class RenderPdf < Prawn::Document
protected
def fontsize(n)
n
def fontsize(size)
size
end
# return whether pagebreak or vertical whitespace is used for breaks

View file

@ -19,10 +19,10 @@ class TokenVerifier < ActiveSupport::MessageVerifier
raise InvalidPrefix unless r[1] == @_prefix
# return original message
if r.length > 2
return unless r.length > 2
r[2]
end
end
class InvalidMessage < ActiveSupport::MessageVerifier::InvalidSignature; end

View file

@ -81,7 +81,7 @@ class Mailer < ActionMailer::Base
add_order_result_attachments order, options
subject = I18n.t('mailer.order_result_supplier.subject', :name => order.supplier.name)
subject = I18n.t('mailer.order_result_supplier.subject', name: order.supplier.name)
subject += " (#{I18n.t('activerecord.attributes.order.pickup')}: #{format_date(order.pickup)})" if order.pickup
mail to: order.supplier.email,
@ -122,10 +122,11 @@ class Mailer < ActionMailer::Base
if args[:from].is_a? User
args[:reply_to] ||= args[:from]
args[:from] = format_address(FoodsoftConfig[:email_sender], I18n.t('mailer.from_via_foodsoft', name: show_user(args[:from])))
args[:from] =
format_address(FoodsoftConfig[:email_sender], I18n.t('mailer.from_via_foodsoft', name: show_user(args[:from])))
end
[:bcc, :cc, :reply_to, :sender, :to].each do |k|
%i[bcc cc reply_to sender to].each do |k|
user = args[k]
args[k] = format_address(user.email, show_user(user)) if user.is_a? User
end
@ -145,21 +146,21 @@ class Mailer < ActionMailer::Base
def self.deliver_now_with_user_locale(user, &block)
I18n.with_locale(user.settings['profile']['language']) do
self.deliver_now(&block)
deliver_now(&block)
end
end
def self.deliver_now_with_default_locale(&block)
I18n.with_locale(FoodsoftConfig[:default_locale]) do
self.deliver_now(&block)
deliver_now(&block)
end
end
def self.deliver_now
message = yield
message.deliver_now
rescue => error
MailDeliveryStatus.create email: message.to[0], message: error.message
rescue StandardError => e
MailDeliveryStatus.create email: message.to[0], message: e.message
end
# separate method to allow plugins to mess with the attachments
@ -169,8 +170,7 @@ class Mailer < ActionMailer::Base
end
# separate method to allow plugins to mess with the text
def additonal_welcome_text(user)
end
def additonal_welcome_text(user); end
private

View file

@ -42,7 +42,7 @@ class Article < ApplicationRecord
belongs_to :supplier
# @!attribute article_prices
# @return [Array<ArticlePrice>] Price history (current price first).
has_many :article_prices, -> { order("created_at DESC") }
has_many :article_prices, -> { order('created_at DESC') }
# @!attribute order_articles
# @return [Array<OrderArticle>] Order articles for this article.
has_many :order_articles
@ -60,16 +60,16 @@ class Article < ApplicationRecord
scope :not_in_stock, -> { where(type: nil) }
# Validations
validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category
validates_length_of :name, :in => 4..60
validates_length_of :unit, :in => 1..15
validates_length_of :note, :maximum => 255
validates_length_of :origin, :maximum => 255
validates_length_of :manufacturer, :maximum => 255
validates_length_of :order_number, :maximum => 255
validates_numericality_of :price, :greater_than_or_equal_to => 0
validates_numericality_of :unit_quantity, :greater_than => 0
validates_numericality_of :deposit, :tax
validates :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category, presence: true
validates :name, length: { in: 4..60 }
validates :unit, length: { in: 1..15 }
validates :note, length: { maximum: 255 }
validates :origin, length: { maximum: 255 }
validates :manufacturer, length: { maximum: 255 }
validates :order_number, length: { maximum: 255 }
validates :price, numericality: { greater_than_or_equal_to: 0 }
validates :unit_quantity, numericality: { greater_than: 0 }
validates :deposit, :tax, numericality: true
# validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type], if: Proc.new {|a| a.supplier.shared_sync_method.blank? or a.supplier.shared_sync_method == 'import' }
# validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type, :unit, :unit_quantity]
validate :uniqueness_of_name
@ -78,12 +78,12 @@ class Article < ApplicationRecord
before_save :update_price_history
before_destroy :check_article_in_use
def self.ransackable_attributes(auth_object = nil)
%w(id name supplier_id article_category_id unit note manufacturer origin unit_quantity order_number)
def self.ransackable_attributes(_auth_object = nil)
%w[id name supplier_id article_category_id unit note manufacturer origin unit_quantity order_number]
end
def self.ransackable_associations(auth_object = nil)
%w(article_category supplier order_articles orders)
def self.ransackable_associations(_auth_object = nil)
%w[article_category supplier order_articles orders]
end
# Returns true if article has been updated at least 2 days ago
@ -96,7 +96,7 @@ class Article < ApplicationRecord
@in_open_order ||= begin
order_articles = OrderArticle.where(order_id: Order.open.collect(&:id))
order_article = order_articles.detect { |oa| oa.article_id == id }
order_article ? order_article.order : nil
order_article&.order
end
end
@ -112,17 +112,17 @@ class Article < ApplicationRecord
def shared_article_changed?(supplier = self.supplier)
# skip early if the timestamp hasn't changed
shared_article = self.shared_article(supplier)
unless shared_article.nil? || self.shared_updated_on == shared_article.updated_on
return if shared_article.nil? || shared_updated_on == shared_article.updated_on
attrs = unequal_attributes(shared_article)
if attrs.empty?
# when attributes not changed, update timestamp of article
self.update_attribute(:shared_updated_on, shared_article.updated_on)
update_attribute(:shared_updated_on, shared_article.updated_on)
false
else
attrs
end
end
end
# Return article attributes that were changed (incl. unit conversion)
# @param new_article [Article] New article to update self
@ -131,30 +131,31 @@ class Article < ApplicationRecord
def unequal_attributes(new_article, options = {})
# try to convert different units when desired
if options[:convert_units] == false
new_price, new_unit_quantity = nil, nil
new_price = nil
new_unit_quantity = nil
else
new_price, new_unit_quantity = convert_units(new_article)
end
if new_price && new_unit_quantity
new_unit = self.unit
new_unit = unit
else
new_price = new_article.price
new_unit_quantity = new_article.unit_quantity
new_unit = new_article.unit
end
return Article.compare_attributes(
Article.compare_attributes(
{
:name => [self.name, new_article.name],
:manufacturer => [self.manufacturer, new_article.manufacturer.to_s],
:origin => [self.origin, new_article.origin],
:unit => [self.unit, new_unit],
:price => [self.price.to_f.round(2), new_price.to_f.round(2)],
:tax => [self.tax, new_article.tax],
:deposit => [self.deposit.to_f.round(2), new_article.deposit.to_f.round(2)],
name: [name, new_article.name],
manufacturer: [manufacturer, new_article.manufacturer.to_s],
origin: [origin, new_article.origin],
unit: [unit, new_unit],
price: [price.to_f.round(2), new_price.to_f.round(2)],
tax: [tax, new_article.tax],
deposit: [deposit.to_f.round(2), new_article.deposit.to_f.round(2)],
# take care of different num-objects.
:unit_quantity => [self.unit_quantity.to_s.to_f, new_unit_quantity.to_s.to_f],
:note => [self.note.to_s, new_article.note.to_s]
unit_quantity: [unit_quantity.to_s.to_f, new_unit_quantity.to_s.to_f],
note: [note.to_s, new_article.note.to_s]
}
)
end
@ -165,14 +166,20 @@ class Article < ApplicationRecord
# @param attributes [Hash<Symbol, Array>] Attributes with old and new values
# @return [Hash<Symbol, Object>] Changed attributes with new values
def self.compare_attributes(attributes)
unequal_attributes = attributes.select { |name, values| values[0] != values[1] && !(values[0].blank? && values[1].blank?) }
Hash[unequal_attributes.to_a.map { |a| [a[0], a[1].last] }]
unequal_attributes = attributes.select do |_name, values|
values[0] != values[1] && !(values[0].blank? && values[1].blank?)
end
unequal_attributes.to_a.map { |a| [a[0], a[1].last] }.to_h
end
# to get the correspondent shared article
def shared_article(supplier = self.supplier)
self.order_number.blank? and return nil
@shared_article ||= supplier.shared_supplier.find_article_by_number(self.order_number) rescue nil
order_number.blank? and return nil
@shared_article ||= begin
supplier.shared_supplier.find_article_by_number(order_number)
rescue StandardError
nil
end
end
# convert units in foodcoop-size
@ -181,9 +188,10 @@ class Article < ApplicationRecord
# returns false if units aren't foodsoft-compatible
# returns nil if units are eqal
def convert_units(new_article = shared_article)
if unit != new_article.unit
return unless unit != new_article.unit
# legacy, used by foodcoops in Germany
if new_article.unit == "KI" && unit == "ST" # 'KI' means a box, with a different amount of items in it
if new_article.unit == 'KI' && unit == 'ST' # 'KI' means a box, with a different amount of items in it
# try to match the size out of its name, e.g. "banana 10-12 St" => 10
new_unit_quantity = /[0-9\-\s]+(St)/.match(new_article.name).to_s.to_i
if new_unit_quantity && new_unit_quantity > 0
@ -193,8 +201,16 @@ class Article < ApplicationRecord
false
end
else # use ruby-units to convert
fc_unit = (::Unit.new(unit) rescue nil)
supplier_unit = (::Unit.new(new_article.unit) rescue nil)
fc_unit = begin
::Unit.new(unit)
rescue StandardError
nil
end
supplier_unit = begin
::Unit.new(new_article.unit)
rescue StandardError
nil
end
if fc_unit && supplier_unit && fc_unit =~ supplier_unit
conversion_factor = (supplier_unit / fc_unit).to_base.to_r
new_price = new_article.price / conversion_factor
@ -204,9 +220,6 @@ class Article < ApplicationRecord
false
end
end
else
nil
end
end
def deleted?
@ -222,20 +235,20 @@ class Article < ApplicationRecord
# Checks if the article is in use before it will deleted
def check_article_in_use
raise I18n.t('articles.model.error_in_use', :article => self.name.to_s) if self.in_open_order
raise I18n.t('articles.model.error_in_use', article: name.to_s) if in_open_order
end
# Create an ArticlePrice, when the price-attr are changed.
def update_price_history
if price_changed?
return unless price_changed?
article_prices.build(
:price => price,
:tax => tax,
:deposit => deposit,
:unit_quantity => unit_quantity
price: price,
tax: tax,
deposit: deposit,
unit_quantity: unit_quantity
)
end
end
def price_changed?
changed.detect { |attr| attr == 'price' || 'tax' || 'deposit' || 'unit_quantity' } ? true : false
@ -250,8 +263,8 @@ class Article < ApplicationRecord
# supplier should always be there - except, perhaps, on initialization (on seeding)
if supplier && (supplier.shared_sync_method.blank? || supplier.shared_sync_method == 'import')
errors.add :name, :taken if matches.any?
else
errors.add :name, :taken_with_unit if matches.where(unit: unit, unit_quantity: unit_quantity).any?
elsif matches.where(unit: unit, unit_quantity: unit_quantity).any?
errors.add :name, :taken_with_unit
end
end
end

View file

@ -17,16 +17,16 @@ class ArticleCategory < ApplicationRecord
normalize_attributes :name, :description
validates :name, :presence => true, :uniqueness => true, :length => { :minimum => 2 }
validates :name, presence: true, uniqueness: true, length: { minimum: 2 }
before_destroy :check_for_associated_articles
def self.ransackable_attributes(auth_object = nil)
%w(id name)
def self.ransackable_attributes(_auth_object = nil)
%w[id name]
end
def self.ransackable_associations(auth_object = nil)
%w(articles order_articles orders)
def self.ransackable_associations(_auth_object = nil)
%w[articles order_articles orders]
end
# Find a category that matches a category name; may return nil.
@ -40,7 +40,11 @@ class ArticleCategory < ApplicationRecord
# case-insensitive substring match (take the closest match = shortest)
c = ArticleCategory.where('name LIKE ?', "%#{category}%") unless c && c.any?
# case-insensitive phrase present in category description
c = ArticleCategory.where('description LIKE ?', "%#{category}%").select { |s| s.description.match /(^|,)\s*#{category}\s*(,|$)/i } unless c && c.any?
unless c && c.any?
c = ArticleCategory.where('description LIKE ?', "%#{category}%").select do |s|
s.description.match(/(^|,)\s*#{category}\s*(,|$)/i)
end
end
# return closest match if there are multiple
c = c.sort_by { |s| s.name.length }.first if c.respond_to? :sort_by
c
@ -50,6 +54,9 @@ class ArticleCategory < ApplicationRecord
# Deny deleting the category when there are associated articles.
def check_for_associated_articles
raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.undeleted.exists?
return unless articles.undeleted.exists?
raise I18n.t('activerecord.errors.has_many_left',
collection: Article.model_name.human)
end
end

View file

@ -24,8 +24,8 @@ class ArticlePrice < ApplicationRecord
localize_input_of :price, :tax, :deposit
validates_presence_of :price, :tax, :deposit, :unit_quantity
validates_numericality_of :price, :greater_than_or_equal_to => 0
validates_numericality_of :unit_quantity, :greater_than => 0
validates_numericality_of :deposit, :tax
validates :price, :tax, :deposit, :unit_quantity, presence: true
validates :price, numericality: { greater_than_or_equal_to: 0 }
validates :unit_quantity, numericality: { greater_than: 0 }
validates :deposit, :tax, numericality: true
end

View file

@ -5,10 +5,10 @@ class BankAccount < ApplicationRecord
normalize_attributes :name, :iban, :description
validates :name, :presence => true, :uniqueness => true, :length => { :minimum => 2 }
validates :iban, :presence => true, :uniqueness => true
validates_format_of :iban, :with => /\A[A-Z]{2}[0-9]{2}[0-9A-Z]{,30}\z/
validates_numericality_of :balance, :message => I18n.t('bank_account.model.invalid_balance')
validates :name, presence: true, uniqueness: true, length: { minimum: 2 }
validates :iban, presence: true, uniqueness: true
validates :iban, format: { with: /\A[A-Z]{2}[0-9]{2}[0-9A-Z]{,30}\z/ }
validates :balance, numericality: { message: I18n.t('bank_account.model.invalid_balance') }
# @return [Function] Method wich can be called to import transaction from a bank or nil if unsupported
def find_connector
@ -18,10 +18,8 @@ class BankAccount < ApplicationRecord
def assign_unlinked_transactions
count = 0
bank_transactions.without_financial_link.includes(:supplier, :user).each do |t|
if t.assign_to_ordergroup || t.assign_to_invoice
count += 1
end
bank_transactions.without_financial_link.includes(:supplier, :user).find_each do |t|
count += 1 if t.assign_to_ordergroup || t.assign_to_invoice
end
count
end

View file

@ -4,5 +4,5 @@ class BankGateway < ApplicationRecord
scope :with_unattended_support, -> { where.not(unattended_user: nil) }
validates_presence_of :name, :url
validates :name, :url, presence: true
end

View file

@ -22,8 +22,8 @@ class BankTransaction < ApplicationRecord
belongs_to :supplier, optional: true, foreign_key: 'iban', primary_key: 'iban'
belongs_to :user, optional: true, foreign_key: 'iban', primary_key: 'iban'
validates_presence_of :date, :amount, :bank_account_id
validates_numericality_of :amount
validates :date, :amount, :bank_account_id, presence: true
validates :amount, numericality: true
scope :without_financial_link, -> { where(financial_link: nil) }
@ -31,13 +31,13 @@ class BankTransaction < ApplicationRecord
localize_input_of :amount
def image_url
'data:image/png;base64,' + Base64.encode64(self.image)
'data:image/png;base64,' + Base64.encode64(image)
end
def assign_to_invoice
return false unless supplier
content = text || ""
content = text || ''
content += "\n" + reference if reference.present?
invoices = supplier.invoices.unpaid.select { |i| content.include? i.number }
invoices_sum = invoices.map(&:amount).sum
@ -49,7 +49,7 @@ class BankTransaction < ApplicationRecord
update_attribute :financial_link, link
end
return true
true
end
def assign_to_ordergroup
@ -78,6 +78,6 @@ class BankTransaction < ApplicationRecord
update_attribute :financial_link, link
end
return true
true
end
end

View file

@ -10,7 +10,7 @@ module CustomFields
end
after_save do
self.settings.custom_fields = custom_fields if custom_fields
settings.custom_fields = custom_fields if custom_fields
end
end
end

View file

@ -3,9 +3,9 @@ module FindEachWithOrder
extend ActiveSupport::Concern
class_methods do
def find_each_with_order(options = {})
def find_each_with_order(options = {}, &block)
find_in_batches_with_order(options) do |records|
records.each { |record| yield record }
records.each(&block)
end
end

View file

@ -5,12 +5,12 @@ module LocalizeInput
return input unless input.is_a? String
Rails.logger.debug { "Input: #{input.inspect}" }
separator = I18n.t("separator", scope: "number.format")
delimiter = I18n.t("delimiter", scope: "number.format")
input.gsub!(delimiter, "") if input.match(/\d+#{Regexp.escape(delimiter)}+\d+#{Regexp.escape(separator)}+\d+/) # Remove delimiter
input.gsub!(separator, ".") # Replace separator with db compatible character
separator = I18n.t('separator', scope: 'number.format')
delimiter = I18n.t('delimiter', scope: 'number.format')
input.gsub!(delimiter, '') if input.match(/\d+#{Regexp.escape(delimiter)}+\d+#{Regexp.escape(separator)}+\d+/) # Remove delimiter
input.gsub!(separator, '.') # Replace separator with db compatible character
input
rescue
rescue StandardError
Rails.logger.warn "Can't localize input: #{input}"
input
end

View file

@ -3,7 +3,7 @@ module MarkAsDeletedWithName
def mark_as_deleted
# get maximum length of name
max_length = 100000
max_length = 100_000
if lenval = self.class.validators_on(:name).detect { |v| v.is_a?(ActiveModel::Validations::LengthValidator) }
max_length = lenval.options[:maximum]
end

View file

@ -15,6 +15,6 @@ module PriceCalculation
private
def add_percent(value, percent)
(value * (percent * 0.01 + 1)).round(2)
(value * ((percent * 0.01) + 1)).round(2)
end
end

View file

@ -4,10 +4,10 @@ class Delivery < StockEvent
scope :recent, -> { order('created_at DESC').limit(10) }
validates_presence_of :supplier_id
validates :supplier_id, presence: true
validate :stock_articles_must_be_unique
accepts_nested_attributes_for :stock_changes, :allow_destroy => :true
accepts_nested_attributes_for :stock_changes, allow_destroy: :true
def new_stock_changes=(stock_change_attributes)
for attributes in stock_change_attributes
@ -16,7 +16,7 @@ class Delivery < StockEvent
end
def includes_article?(article)
self.stock_changes.map { |stock_change| stock_change.stock_article.id }.include? article.id
stock_changes.map { |stock_change| stock_change.stock_article.id }.include? article.id
end
def sum(type = :gross)
@ -39,8 +39,8 @@ class Delivery < StockEvent
protected
def stock_articles_must_be_unique
unless stock_changes.reject { |sc| sc.marked_for_destruction? }.map { |sc| sc.stock_article.id }.uniq!.nil?
return if stock_changes.reject { |sc| sc.marked_for_destruction? }.map { |sc| sc.stock_article.id }.uniq!.nil?
errors.add(:base, I18n.t('model.delivery.each_stock_article_must_be_unique'))
end
end
end

View file

@ -4,13 +4,13 @@ class FinancialLink < ApplicationRecord
has_many :invoices
scope :incomplete, -> { with_full_sum.where.not('full_sums.full_sum' => 0) }
scope :unused, -> {
scope :unused, lambda {
includes(:bank_transactions, :financial_transactions, :invoices)
.where(bank_transactions: { financial_link_id: nil })
.where(financial_transactions: { financial_link_id: nil })
.where(invoices: { financial_link_id: nil })
}
scope :with_full_sum, -> {
scope :with_full_sum, lambda {
select(:id, :note, :full_sum).joins(<<-SQL)
LEFT JOIN (
SELECT id, COALESCE(bt_sum, 0) - COALESCE(ft_sum, 0) + COALESCE(i_sum, 0) AS full_sum

Some files were not shown because too many files have changed in this diff Show more