Run rubocop --fix-layout and remove encoding comments
This commit is contained in:
parent
fa63e6e81d
commit
ea2862fdef
283 changed files with 1164 additions and 1969 deletions
|
|
@ -1,4 +1,3 @@
|
|||
# encoding: utf-8
|
||||
class Article < ApplicationRecord
|
||||
include PriceCalculation
|
||||
|
||||
|
|
@ -66,8 +65,8 @@ class Article < ApplicationRecord
|
|||
validates_numericality_of :price, :greater_than_or_equal_to => 0
|
||||
validates_numericality_of :unit_quantity, :greater_than => 0
|
||||
validates_numericality_of :deposit, :tax
|
||||
#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]
|
||||
# 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
|
||||
|
||||
# Callbacks
|
||||
|
|
@ -91,7 +90,7 @@ class Article < ApplicationRecord
|
|||
def in_open_order
|
||||
@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_articles.detect { |oa| oa.article_id == id }
|
||||
order_article ? order_article.order : nil
|
||||
end
|
||||
end
|
||||
|
|
@ -124,7 +123,7 @@ class Article < ApplicationRecord
|
|||
# @param new_article [Article] New article to update self
|
||||
# @option options [Boolean] :convert_units Omit or set to +true+ to keep current unit and recompute unit quantity and price.
|
||||
# @return [Hash<Symbol, Object>] Attributes with new values
|
||||
def unequal_attributes(new_article, options={})
|
||||
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
|
||||
|
|
@ -162,7 +161,7 @@ class Article < ApplicationRecord
|
|||
# @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]}]
|
||||
Hash[unequal_attributes.to_a.map { |a| [a[0], a[1].last] }]
|
||||
end
|
||||
|
||||
# to get the correspondent shared article
|
||||
|
|
@ -183,7 +182,7 @@ class Article < ApplicationRecord
|
|||
# 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
|
||||
new_price = (new_article.price/new_unit_quantity.to_f).round(2)
|
||||
new_price = (new_article.price / new_unit_quantity.to_f).round(2)
|
||||
[new_price, new_unit_quantity]
|
||||
else
|
||||
false
|
||||
|
|
@ -250,5 +249,4 @@ class Article < ApplicationRecord
|
|||
errors.add :name, :taken_with_unit if matches.where(unit: unit, unit_quantity: unit_quantity).any?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
# Article category
|
||||
class ArticleCategory < ApplicationRecord
|
||||
|
||||
# @!attribute name
|
||||
# @return [String] Title of the category.
|
||||
# @!attrubute description
|
||||
|
|
@ -34,15 +33,16 @@ class ArticleCategory < ApplicationRecord
|
|||
# TODO more intelligence like remembering earlier associations (global and/or per-supplier)
|
||||
def self.find_match(category)
|
||||
return if category.blank? || category.length < 3
|
||||
|
||||
c = nil
|
||||
## exact match - not needed, will be returned by next query as well
|
||||
#c ||= ArticleCategory.where(name: category).first
|
||||
# c ||= ArticleCategory.where(name: category).first
|
||||
# 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?
|
||||
c = ArticleCategory.where('description LIKE ?', "%#{category}%").select { |s| s.description.match /(^|,)\s*#{category}\s*(,|$)/i } unless c && c.any?
|
||||
# return closest match if there are multiple
|
||||
c = c.sort_by {|s| s.name.length}.first if c.respond_to? :sort_by
|
||||
c = c.sort_by { |s| s.name.length }.first if c.respond_to? :sort_by
|
||||
c
|
||||
end
|
||||
|
||||
|
|
@ -52,5 +52,4 @@ class ArticleCategory < ApplicationRecord
|
|||
def check_for_associated_articles
|
||||
raise I18n.t('activerecord.errors.has_many_left', collection: Article.model_name.human) if articles.undeleted.exists?
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,5 +27,4 @@ class ArticlePrice < ApplicationRecord
|
|||
validates_numericality_of :price, :greater_than_or_equal_to => 0
|
||||
validates_numericality_of :unit_quantity, :greater_than => 0
|
||||
validates_numericality_of :deposit, :tax
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class Assignment < ApplicationRecord
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :task
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class BankAccount < ApplicationRecord
|
||||
|
||||
has_many :bank_transactions, dependent: :destroy
|
||||
|
||||
normalize_attributes :name, :iban, :description
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class BankTransaction < ApplicationRecord
|
||||
|
||||
# @!attribute external_id
|
||||
# @return [String] Unique Identifier of the transaction within the bank account.
|
||||
# @!attribute date
|
||||
|
|
@ -39,13 +38,13 @@ class BankTransaction < ApplicationRecord
|
|||
|
||||
content = text
|
||||
content += "\n" + reference if reference.present?
|
||||
invoices = supplier.invoices.unpaid.select {|i| content.include? i.number}
|
||||
invoices = supplier.invoices.unpaid.select { |i| content.include? i.number }
|
||||
invoices_sum = invoices.map(&:amount).sum
|
||||
return false if amount != -invoices_sum
|
||||
|
||||
transaction do
|
||||
link = FinancialLink.new
|
||||
invoices.each {|i| i.update_attributes! financial_link: link, paid_on: date }
|
||||
invoices.each { |i| i.update_attributes! financial_link: link, paid_on: date }
|
||||
update_attribute :financial_link, link
|
||||
end
|
||||
|
||||
|
|
@ -57,8 +56,10 @@ class BankTransaction < ApplicationRecord
|
|||
return unless m
|
||||
|
||||
return false if m[:parts].values.sum != amount
|
||||
|
||||
group = Ordergroup.find_by_id(m[:group])
|
||||
return false unless group
|
||||
|
||||
usr = m[:user] ? User.find_by_id(m[:user]) : group.users.first
|
||||
return false unless usr
|
||||
|
||||
|
|
@ -69,6 +70,7 @@ class BankTransaction < ApplicationRecord
|
|||
m[:parts].each do |short, value|
|
||||
ftt = FinancialTransactionType.find_by_name_short(short)
|
||||
return false unless ftt
|
||||
|
||||
group.add_financial_transaction! value, note, usr, ftt, link if value > 0
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module CustomFields
|
|||
|
||||
included do
|
||||
after_initialize do
|
||||
settings.defaults['custom_fields'] = { } unless settings.custom_fields
|
||||
settings.defaults['custom_fields'] = {} unless settings.custom_fields
|
||||
end
|
||||
|
||||
after_save do
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ module FindEachWithOrder
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
|
||||
def find_each_with_order(options = {})
|
||||
find_in_batches_with_order(options) do |records|
|
||||
records.each { |record| yield record }
|
||||
|
|
@ -34,6 +33,5 @@ module FindEachWithOrder
|
|||
records = relation.offset(start).to_a
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module MarkAsDeletedWithName
|
|||
n = ''
|
||||
begin
|
||||
append = " \u2020" + n
|
||||
deleted_name = name.truncate(max_length-append.length, omission: '') + append
|
||||
deleted_name = name.truncate(max_length - append.length, omission: '') + append
|
||||
if n.blank?
|
||||
n = 'A'
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class Delivery < StockEvent
|
||||
|
||||
belongs_to :supplier
|
||||
belongs_to :invoice, optional: true
|
||||
|
||||
|
|
@ -17,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
|
||||
self.stock_changes.map { |stock_change| stock_change.stock_article.id }.include? article.id
|
||||
end
|
||||
|
||||
def sum(type = :gross)
|
||||
|
|
@ -26,12 +25,12 @@ class Delivery < StockEvent
|
|||
article = sc.stock_article
|
||||
quantity = sc.quantity
|
||||
case type
|
||||
when :net
|
||||
total += quantity * article.price
|
||||
when :gross
|
||||
total += quantity * article.gross_price
|
||||
when :fc
|
||||
total += quantity * article.fc_price
|
||||
when :net
|
||||
total += quantity * article.price
|
||||
when :gross
|
||||
total += quantity * article.gross_price
|
||||
when :fc
|
||||
total += quantity * article.fc_price
|
||||
end
|
||||
end
|
||||
total
|
||||
|
|
@ -40,9 +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?
|
||||
unless 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
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class FinancialLink < ApplicationRecord
|
|||
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})
|
||||
.where(invoices: { financial_link_id: nil })
|
||||
}
|
||||
scope :with_full_sum, -> {
|
||||
select(:id, :note, :full_sum).joins(<<-SQL)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class FinancialTransaction < ApplicationRecord
|
|||
|
||||
validates_presence_of :amount, :note, :user_id
|
||||
validates_numericality_of :amount, greater_then: -100_000,
|
||||
less_than: 100_000
|
||||
less_than: 100_000
|
||||
|
||||
scope :visible, -> { joins('LEFT JOIN financial_transactions r ON financial_transactions.id = r.reverts_id').where('r.id IS NULL').where(reverts: nil) }
|
||||
scope :without_financial_link, -> { where(financial_link: nil) }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# encoding: utf-8
|
||||
# Groups organize the User.
|
||||
# A Member gets the roles from the Group
|
||||
class Group < ApplicationRecord
|
||||
|
|
@ -8,7 +7,7 @@ class Group < ApplicationRecord
|
|||
has_many :memberships, dependent: :destroy
|
||||
has_many :users, -> { where(deleted_at: nil) }, through: :memberships
|
||||
|
||||
validates :name, :presence => true, :length => {:in => 1..25}
|
||||
validates :name, :presence => true, :length => { :in => 1..25 }
|
||||
validates_uniqueness_of :name
|
||||
|
||||
attr_reader :user_tokens
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class GroupOrder < ApplicationRecord
|
|||
|
||||
validates_presence_of :order_id
|
||||
validates_numericality_of :price
|
||||
validates_uniqueness_of :ordergroup_id, :scope => :order_id # order groups can only order once per order
|
||||
validates_uniqueness_of :ordergroup_id, :scope => :order_id # order groups can only order once per order
|
||||
|
||||
scope :in_open_orders, -> { joins(:order).merge(Order.open) }
|
||||
scope :in_finished_orders, -> { joins(:order).merge(Order.finished_not_closed) }
|
||||
|
|
@ -39,23 +39,22 @@ class GroupOrder < ApplicationRecord
|
|||
data[:order_articles] = {}
|
||||
order.articles_grouped_by_category.each do |article_category, order_articles|
|
||||
order_articles.each do |order_article|
|
||||
|
||||
# Get the result of last time ordering, if possible
|
||||
goa = group_order_articles.detect { |goa| goa.order_article_id == order_article.id }
|
||||
|
||||
# Build hash with relevant data
|
||||
data[:order_articles][order_article.id] = {
|
||||
:price => order_article.article.fc_price,
|
||||
:unit => order_article.article.unit_quantity,
|
||||
:quantity => (goa ? goa.quantity : 0),
|
||||
:others_quantity => order_article.quantity - (goa ? goa.quantity : 0),
|
||||
:used_quantity => (goa ? goa.result(:quantity) : 0),
|
||||
:tolerance => (goa ? goa.tolerance : 0),
|
||||
:others_tolerance => order_article.tolerance - (goa ? goa.tolerance : 0),
|
||||
:used_tolerance => (goa ? goa.result(:tolerance) : 0),
|
||||
:total_price => (goa ? goa.total_price : 0),
|
||||
:missing_units => order_article.missing_units,
|
||||
:quantity_available => (order.stockit? ? order_article.article.quantity_available : 0)
|
||||
:price => order_article.article.fc_price,
|
||||
:unit => order_article.article.unit_quantity,
|
||||
:quantity => (goa ? goa.quantity : 0),
|
||||
:others_quantity => order_article.quantity - (goa ? goa.quantity : 0),
|
||||
:used_quantity => (goa ? goa.result(:quantity) : 0),
|
||||
:tolerance => (goa ? goa.tolerance : 0),
|
||||
:others_tolerance => order_article.tolerance - (goa ? goa.tolerance : 0),
|
||||
:used_tolerance => (goa ? goa.result(:tolerance) : 0),
|
||||
:total_price => (goa ? goa.total_price : 0),
|
||||
:missing_units => order_article.missing_units,
|
||||
:quantity_available => (order.stockit? ? order_article.article.quantity_available : 0)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -70,7 +69,7 @@ class GroupOrder < ApplicationRecord
|
|||
|
||||
# Get ordered quantities and update group_order_articles/_quantities...
|
||||
if group_order_articles_attributes
|
||||
quantities = group_order_articles_attributes.fetch(order_article.id.to_s, {:quantity => 0, :tolerance => 0})
|
||||
quantities = group_order_articles_attributes.fetch(order_article.id.to_s, { :quantity => 0, :tolerance => 0 })
|
||||
group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i)
|
||||
end
|
||||
|
||||
|
|
@ -88,7 +87,6 @@ class GroupOrder < ApplicationRecord
|
|||
update_attribute(:price, total)
|
||||
end
|
||||
|
||||
|
||||
# Save GroupOrder and updates group_order_articles/quantities accordingly
|
||||
def save_ordering!
|
||||
transaction do
|
||||
|
|
@ -104,7 +102,7 @@ class GroupOrder < ApplicationRecord
|
|||
|
||||
def total
|
||||
return price + transport if transport
|
||||
|
||||
price
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@
|
|||
# The chronologically order of the Ordergroup - activity are stored in GroupOrderArticleQuantity
|
||||
#
|
||||
class GroupOrderArticle < ApplicationRecord
|
||||
|
||||
belongs_to :group_order
|
||||
belongs_to :order_article
|
||||
has_many :group_order_article_quantities, dependent: :destroy
|
||||
|
||||
validates_presence_of :group_order, :order_article
|
||||
validates_uniqueness_of :order_article_id, :scope => :group_order_id # just once an article per group order
|
||||
validates_uniqueness_of :order_article_id, :scope => :group_order_id # just once an article per group order
|
||||
validate :check_order_not_closed # don't allow changes to closed (aka settled) orders
|
||||
validates :quantity, :tolerance, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
|
||||
|
|
@ -83,10 +82,10 @@ class GroupOrderArticle < ApplicationRecord
|
|||
if (quantity > self.quantity || tolerance > self.tolerance)
|
||||
logger.debug("Inserting a new GroupOrderArticleQuantity")
|
||||
quantities.insert(0, GroupOrderArticleQuantity.new(
|
||||
:group_order_article => self,
|
||||
:quantity => (quantity > self.quantity ? quantity - self.quantity : 0),
|
||||
:tolerance => (tolerance > self.tolerance ? tolerance - self.tolerance : 0)
|
||||
))
|
||||
:group_order_article => self,
|
||||
:quantity => (quantity > self.quantity ? quantity - self.quantity : 0),
|
||||
:tolerance => (tolerance > self.tolerance ? tolerance - self.tolerance : 0)
|
||||
))
|
||||
# Recalc totals:
|
||||
self.quantity += quantities[0].quantity
|
||||
self.tolerance += quantities[0].tolerance
|
||||
|
|
@ -99,11 +98,11 @@ class GroupOrderArticle < ApplicationRecord
|
|||
end
|
||||
|
||||
# Remove zero-only items.
|
||||
quantities = quantities.reject { | q | q.quantity == 0 && q.tolerance == 0}
|
||||
quantities = quantities.reject { |q| q.quantity == 0 && q.tolerance == 0 }
|
||||
|
||||
# Save
|
||||
transaction do
|
||||
quantities.each { | i | i.save! }
|
||||
quantities.each { |i| i.save! }
|
||||
self.group_order_article_quantities = quantities
|
||||
save!
|
||||
end
|
||||
|
|
@ -169,7 +168,7 @@ class GroupOrderArticle < ApplicationRecord
|
|||
end
|
||||
|
||||
# memoize result unless a total is given
|
||||
r = {:quantity => quantity, :tolerance => tolerance, :total => quantity + tolerance}
|
||||
r = { :quantity => quantity, :tolerance => tolerance, :total => quantity + tolerance }
|
||||
@calculate_result = r if total.nil?
|
||||
r
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
# Considers every update of an article-order, so may rows for one group_order_article ar possible.
|
||||
|
||||
class GroupOrderArticleQuantity < ApplicationRecord
|
||||
|
||||
belongs_to :group_order_article
|
||||
|
||||
validates_presence_of :group_order_article_id
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class Invite < ApplicationRecord
|
|||
|
||||
before_validation :set_token_and_expires_at
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
# Before validation, set token and expires_at.
|
||||
def set_token_and_expires_at
|
||||
|
|
@ -22,7 +22,7 @@ class Invite < ApplicationRecord
|
|||
self.expires_at = Time.now.advance(:days => 7)
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# Custom validation: check that email does not already belong to a registered user.
|
||||
def email_not_already_registered
|
||||
|
|
@ -30,5 +30,4 @@ class Invite < ApplicationRecord
|
|||
errors.add(:email, I18n.t('invites.errors.already_member'))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
class Membership < ApplicationRecord
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :group
|
||||
|
||||
before_destroy :check_last_admin
|
||||
|
||||
|
||||
protected
|
||||
|
||||
# check if this is the last admin-membership and deny
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# encoding: utf-8
|
||||
#
|
||||
class Order < ApplicationRecord
|
||||
attr_accessor :ignore_warnings, :transport_distribution
|
||||
|
||||
|
|
@ -71,8 +69,8 @@ class Order < ApplicationRecord
|
|||
if stockit?
|
||||
# make sure to include those articles which are no longer available
|
||||
# but which have already been ordered in this stock order
|
||||
StockArticle.available.includes(:article_category).
|
||||
order('article_categories.name', 'articles.name').reject{ |a|
|
||||
StockArticle.available.includes(:article_category)
|
||||
.order('article_categories.name', 'articles.name').reject { |a|
|
||||
a.quantity_available <= 0 && !a.ordered_in_order?(self)
|
||||
}.group_by { |a| a.article_category.name }
|
||||
else
|
||||
|
|
@ -151,7 +149,7 @@ class Order < ApplicationRecord
|
|||
def self.ordergroup_group_orders_map(ordergroup)
|
||||
orders = includes(:supplier)
|
||||
group_orders = GroupOrder.where(ordergroup_id: ordergroup.id, order_id: orders.map(&:id))
|
||||
group_orders_hash = Hash[group_orders.collect {|go| [go.order_id, go]}]
|
||||
group_orders_hash = Hash[group_orders.collect { |go| [go.order_id, go] }]
|
||||
orders.map do |order|
|
||||
{
|
||||
order: order,
|
||||
|
|
@ -173,22 +171,22 @@ class Order < ApplicationRecord
|
|||
# The array has the following form:
|
||||
# e.g: [["drugs",[teethpaste, toiletpaper]], ["fruits" => [apple, banana, lemon]]]
|
||||
def articles_grouped_by_category
|
||||
@articles_grouped_by_category ||= order_articles.
|
||||
includes([:article_price, :group_order_articles, :article => :article_category]).
|
||||
order('articles.name').
|
||||
group_by { |a| a.article.article_category.name }.
|
||||
sort { |a, b| a[0] <=> b[0] }
|
||||
@articles_grouped_by_category ||= order_articles
|
||||
.includes([:article_price, :group_order_articles, :article => :article_category])
|
||||
.order('articles.name')
|
||||
.group_by { |a| a.article.article_category.name }
|
||||
.sort { |a, b| a[0] <=> b[0] }
|
||||
end
|
||||
|
||||
def articles_sort_by_category
|
||||
order_articles.includes(:article).order('articles.name').sort do |a,b|
|
||||
order_articles.includes(:article).order('articles.name').sort do |a, b|
|
||||
a.article.article_category.name <=> b.article.article_category.name
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the defecit/benefit for the foodcoop
|
||||
# Requires a valid invoice, belonging to this order
|
||||
#FIXME: Consider order.foodcoop_result
|
||||
# FIXME: Consider order.foodcoop_result
|
||||
def profit(options = {})
|
||||
markup = options[:without_markup] || false
|
||||
if invoice
|
||||
|
|
@ -208,22 +206,22 @@ class Order < ApplicationRecord
|
|||
for oa in order_articles.ordered.includes(:article, :article_price)
|
||||
quantity = oa.units * oa.price.unit_quantity
|
||||
case type
|
||||
when :net
|
||||
total += quantity * oa.price.price
|
||||
when :gross
|
||||
total += quantity * oa.price.gross_price
|
||||
when :fc
|
||||
total += quantity * oa.price.fc_price
|
||||
when :net
|
||||
total += quantity * oa.price.price
|
||||
when :gross
|
||||
total += quantity * oa.price.gross_price
|
||||
when :fc
|
||||
total += quantity * oa.price.fc_price
|
||||
end
|
||||
end
|
||||
elsif type == :groups || type == :groups_without_markup
|
||||
for go in group_orders.includes(group_order_articles: {order_article: [:article, :article_price]})
|
||||
for go in group_orders.includes(group_order_articles: { order_article: [:article, :article_price] })
|
||||
for goa in go.group_order_articles
|
||||
case type
|
||||
when :groups
|
||||
total += goa.result * goa.order_article.price.fc_price
|
||||
when :groups_without_markup
|
||||
total += goa.result * goa.order_article.price.gross_price
|
||||
when :groups
|
||||
total += goa.result * goa.order_article.price.fc_price
|
||||
when :groups_without_markup
|
||||
total += goa.result * goa.order_article.price.gross_price
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -251,7 +249,7 @@ class Order < ApplicationRecord
|
|||
# A: Yes, we do - for redistributing articles when the number of articles
|
||||
# delivered changes, and for statistics on popular articles. Records
|
||||
# with both tolerance and quantity zero can be deleted.
|
||||
#goa.group_order_article_quantities.clear
|
||||
# goa.group_order_article_quantities.clear
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -279,7 +277,7 @@ class Order < ApplicationRecord
|
|||
if stockit? # Decreases the quantity of stock_articles
|
||||
for oa in order_articles.includes(:article)
|
||||
oa.update_results! # Update units_to_order of order_article
|
||||
stock_changes.create! :stock_article => oa.article, :quantity => oa.units_to_order*-1
|
||||
stock_changes.create! :stock_article => oa.article, :quantity => oa.units_to_order * -1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -290,6 +288,7 @@ class Order < ApplicationRecord
|
|||
# Close the order directly, without automaticly updating ordergroups account balances
|
||||
def close_direct!(user)
|
||||
raise I18n.t('orders.model.error_closed') if closed?
|
||||
|
||||
comments.create(user: user, text: I18n.t('orders.model.close_direct_message')) unless FoodsoftConfig[:charge_members_manually]
|
||||
update_attributes! state: 'closed', updated_by: user
|
||||
end
|
||||
|
|
@ -319,7 +318,7 @@ class Order < ApplicationRecord
|
|||
begin
|
||||
order.do_end_action!
|
||||
rescue => error
|
||||
ExceptionNotifier.notify_exception(error, data: {foodcoop: FoodsoftConfig.scope, order_id: order.id})
|
||||
ExceptionNotifier.notify_exception(error, data: { foodcoop: FoodsoftConfig.scope, order_id: order.id })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -328,9 +327,9 @@ class Order < ApplicationRecord
|
|||
|
||||
def starts_before_ends
|
||||
delta = Rails.env.test? ? 1 : 0 # since Rails 4.2 tests appear to have time differences, with this validation failing
|
||||
errors.add(:ends, I18n.t('orders.model.error_starts_before_ends')) if ends && starts && ends <= (starts-delta)
|
||||
errors.add(:ends, I18n.t('orders.model.error_boxfill_before_ends')) if ends && boxfill && ends <= (boxfill-delta)
|
||||
errors.add(:boxfill, I18n.t('orders.model.error_starts_before_boxfill')) if boxfill && starts && boxfill <= (starts-delta)
|
||||
errors.add(:ends, I18n.t('orders.model.error_starts_before_ends')) if ends && starts && ends <= (starts - delta)
|
||||
errors.add(:ends, I18n.t('orders.model.error_boxfill_before_ends')) if ends && boxfill && ends <= (boxfill - delta)
|
||||
errors.add(:boxfill, I18n.t('orders.model.error_starts_before_boxfill')) if boxfill && starts && boxfill <= (starts - delta)
|
||||
end
|
||||
|
||||
def include_articles
|
||||
|
|
@ -362,6 +361,7 @@ class Order < ApplicationRecord
|
|||
|
||||
def distribute_transport
|
||||
return unless group_orders.any?
|
||||
|
||||
case transport_distribution.try(&:to_i)
|
||||
when Order.transport_distributions[:ordergroup] then
|
||||
amount = transport / group_orders.size
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class OrderArticle < ApplicationRecord
|
|||
def units
|
||||
return units_received unless units_received.nil?
|
||||
return units_billed unless units_billed.nil?
|
||||
|
||||
units_to_order
|
||||
end
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ class OrderArticle < ApplicationRecord
|
|||
# In balancing this can differ from ordered (by supplier) quantity for this article.
|
||||
def group_orders_sum
|
||||
quantity = group_order_articles.collect(&:result).sum
|
||||
{:quantity => quantity, :price => quantity * price.fc_price}
|
||||
{ :quantity => quantity, :price => quantity * price.fc_price }
|
||||
end
|
||||
|
||||
# Update quantity/tolerance/units_to_order from group_order_articles
|
||||
|
|
@ -96,7 +97,7 @@ class OrderArticle < ApplicationRecord
|
|||
units * price.unit_quantity * price.gross_price
|
||||
end
|
||||
|
||||
def ordered_quantities_different_from_group_orders?(ordered_mark="!", billed_mark="?", received_mark="?")
|
||||
def ordered_quantities_different_from_group_orders?(ordered_mark = "!", billed_mark = "?", received_mark = "?")
|
||||
if not units_received.nil?
|
||||
((units_received * price.unit_quantity) == group_orders_sum[:quantity]) ? false : received_mark
|
||||
elsif not units_billed.nil?
|
||||
|
|
@ -123,12 +124,12 @@ class OrderArticle < ApplicationRecord
|
|||
if surplus.index(:tolerance).nil?
|
||||
qty_for_members = [qty_left, self.quantity].min
|
||||
else
|
||||
qty_for_members = [qty_left, self.quantity+self.tolerance].min
|
||||
counts[surplus.index(:tolerance)] = [0, qty_for_members-self.quantity].max
|
||||
qty_for_members = [qty_left, self.quantity + self.tolerance].min
|
||||
counts[surplus.index(:tolerance)] = [0, qty_for_members - self.quantity].max
|
||||
end
|
||||
|
||||
# Recompute
|
||||
group_order_articles.each {|goa| goa.save_results! qty_for_members }
|
||||
group_order_articles.each { |goa| goa.save_results! qty_for_members }
|
||||
qty_left -= qty_for_members
|
||||
|
||||
# if there's anything left, move to stock if wanted
|
||||
|
|
@ -185,7 +186,7 @@ class OrderArticle < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_global_price=(value)
|
||||
@update_global_price = (value == true || value == '1') ? true : false
|
||||
@update_global_price = (value == true || value == '1') ? true : false
|
||||
end
|
||||
|
||||
# @return [Number] Units missing for the last +unit_quantity+ of the article.
|
||||
|
|
@ -199,7 +200,7 @@ class OrderArticle < ApplicationRecord
|
|||
|
||||
# Check if the result of any associated GroupOrderArticle was overridden manually
|
||||
def result_manually_changed?
|
||||
group_order_articles.any? {|goa| goa.result_manually_changed?}
|
||||
group_order_articles.any? { |goa| goa.result_manually_changed? }
|
||||
end
|
||||
|
||||
def difference_received_ordered
|
||||
|
|
@ -245,7 +246,7 @@ class OrderArticle < ApplicationRecord
|
|||
end
|
||||
|
||||
def _missing_units(unit_quantity, quantity, tolerance)
|
||||
units = unit_quantity - ((quantity % unit_quantity) + tolerance)
|
||||
units = unit_quantity - ((quantity % unit_quantity) + tolerance)
|
||||
units = 0 if units < 0
|
||||
units = 0 if units == unit_quantity
|
||||
units
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class OrderComment < ApplicationRecord
|
||||
|
||||
belongs_to :order
|
||||
belongs_to :user
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
# encoding: utf-8
|
||||
#
|
||||
# Ordergroups can order, they are "children" of the class Group
|
||||
#
|
||||
#
|
||||
# Ordergroup have the following attributes, in addition to Group
|
||||
# * account_balance (decimal)
|
||||
class Ordergroup < Group
|
||||
include CustomFields
|
||||
|
||||
APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
|
||||
APPLE_MONTH_AGO = 6 # How many month back we will count tasks and orders sum
|
||||
|
||||
serialize :stats
|
||||
|
||||
|
|
@ -24,6 +23,7 @@ class Ordergroup < Group
|
|||
def contact
|
||||
"#{contact_phone} (#{contact_person})"
|
||||
end
|
||||
|
||||
def non_members
|
||||
User.natural_order.all.reject { |u| (users.include?(u) || u.ordergroup) }
|
||||
end
|
||||
|
|
@ -43,6 +43,7 @@ class Ordergroup < Group
|
|||
def self.custom_fields
|
||||
fields = FoodsoftConfig[:custom_fields] && FoodsoftConfig[:custom_fields][:ordergroup]
|
||||
return [] unless fields
|
||||
|
||||
fields.map(&:deep_symbolize_keys)
|
||||
end
|
||||
|
||||
|
|
@ -59,11 +60,11 @@ class Ordergroup < Group
|
|||
end
|
||||
|
||||
def value_of_open_orders(exclude = nil)
|
||||
group_orders.in_open_orders.reject{|go| go == exclude}.collect(&:price).sum
|
||||
group_orders.in_open_orders.reject { |go| go == exclude }.collect(&:price).sum
|
||||
end
|
||||
|
||||
|
||||
def value_of_finished_orders(exclude = nil)
|
||||
group_orders.in_finished_orders.reject{|go| go == exclude}.collect(&:price).sum
|
||||
group_orders.in_finished_orders.reject { |go| go == exclude }.collect(&:price).sum
|
||||
end
|
||||
|
||||
# Returns the available funds for this order group (the account_balance minus price of all non-closed GroupOrders of this group).
|
||||
|
|
@ -75,7 +76,7 @@ class Ordergroup < Group
|
|||
def financial_transaction_class_balance(klass)
|
||||
financial_transactions
|
||||
.joins(:financial_transaction_type)
|
||||
.where(financial_transaction_types: {financial_transaction_class_id: klass})
|
||||
.where(financial_transaction_types: { financial_transaction_class_id: klass })
|
||||
.sum(:amount)
|
||||
end
|
||||
|
||||
|
|
@ -101,14 +102,14 @@ class Ordergroup < Group
|
|||
orders_sum = group_orders.includes(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).references(:orders).sum(:price)
|
||||
|
||||
@readonly = false # Dirty hack, avoid getting RecordReadOnly exception when called in task after_save callback. A rails bug?
|
||||
update_attribute(:stats, {:jobs_size => jobs, :orders_sum => orders_sum})
|
||||
update_attribute(:stats, { :jobs_size => jobs, :orders_sum => orders_sum })
|
||||
end
|
||||
|
||||
def update_balance!
|
||||
new_account_balance = financial_transactions
|
||||
.joins(financial_transaction_type: [:financial_transaction_class])
|
||||
.where({ financial_transaction_classes: { ignore_for_account_balance: false} })
|
||||
.sum(:amount)
|
||||
.joins(financial_transaction_type: [:financial_transaction_class])
|
||||
.where({ financial_transaction_classes: { ignore_for_account_balance: false } })
|
||||
.sum(:amount)
|
||||
update_attribute :account_balance, new_account_balance
|
||||
end
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ class Ordergroup < Group
|
|||
stats[:jobs_size].to_f / stats[:orders_sum].to_f rescue 0
|
||||
end
|
||||
|
||||
# This is the ordergroup job per euro performance
|
||||
# This is the ordergroup job per euro performance
|
||||
# in comparison to the hole foodcoop average
|
||||
def apples
|
||||
((avg_jobs_per_euro / Ordergroup.avg_jobs_per_euro) * 100).to_i rescue 0
|
||||
|
|
@ -128,23 +129,23 @@ class Ordergroup < Group
|
|||
# Only ordergroups, which have participated in more than 5 orders in total and more than 2 orders in apple time period
|
||||
def not_enough_apples?
|
||||
FoodsoftConfig[:use_apple_points] &&
|
||||
FoodsoftConfig[:stop_ordering_under].present? &&
|
||||
!ignore_apple_restriction &&
|
||||
apples < FoodsoftConfig[:stop_ordering_under] &&
|
||||
group_orders.count > 5 &&
|
||||
group_orders.joins(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).count > 2
|
||||
FoodsoftConfig[:stop_ordering_under].present? &&
|
||||
!ignore_apple_restriction &&
|
||||
apples < FoodsoftConfig[:stop_ordering_under] &&
|
||||
group_orders.count > 5 &&
|
||||
group_orders.joins(:order).merge(Order.finished).where('orders.ends >= ?', APPLE_MONTH_AGO.month.ago).count > 2
|
||||
end
|
||||
|
||||
# Global average
|
||||
def self.avg_jobs_per_euro
|
||||
stats = Ordergroup.pluck(:stats)
|
||||
stats.sum {|s| s[:jobs_size].to_f } / stats.sum {|s| s[:orders_sum].to_f } rescue 0
|
||||
stats.sum { |s| s[:jobs_size].to_f } / stats.sum { |s| s[:orders_sum].to_f } rescue 0
|
||||
end
|
||||
|
||||
def account_updated
|
||||
financial_transactions.last.try(:created_on) || created_on
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
# Make sure, that a user can only be in one ordergroup
|
||||
|
|
@ -163,6 +164,4 @@ class Ordergroup < Group
|
|||
errors.add :name, message
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ class PeriodicTaskGroup < ApplicationRecord
|
|||
def has_next_task?
|
||||
return false if tasks.empty?
|
||||
return false if tasks.first.due_date.nil?
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class SharedArticle < ApplicationRecord
|
||||
|
||||
# connect to database from sharedLists-Application
|
||||
SharedArticle.establish_connection(FoodsoftConfig[:shared_lists])
|
||||
# set correct table_name in external DB
|
||||
|
|
@ -9,19 +8,19 @@ class SharedArticle < ApplicationRecord
|
|||
|
||||
def build_new_article(supplier)
|
||||
supplier.articles.build(
|
||||
:name => name,
|
||||
:unit => unit,
|
||||
:note => note,
|
||||
:manufacturer => manufacturer,
|
||||
:origin => origin,
|
||||
:price => price,
|
||||
:tax => tax,
|
||||
:deposit => deposit,
|
||||
:unit_quantity => unit_quantity,
|
||||
:order_number => number,
|
||||
:article_category => ArticleCategory.find_match(category),
|
||||
# convert to db-compatible-string
|
||||
:shared_updated_on => updated_on.to_formatted_s(:db)
|
||||
:name => name,
|
||||
:unit => unit,
|
||||
:note => note,
|
||||
:manufacturer => manufacturer,
|
||||
:origin => origin,
|
||||
:price => price,
|
||||
:tax => tax,
|
||||
:deposit => deposit,
|
||||
:unit_quantity => unit_quantity,
|
||||
:order_number => number,
|
||||
:article_category => ArticleCategory.find_match(category),
|
||||
# convert to db-compatible-string
|
||||
:shared_updated_on => updated_on.to_formatted_s(:db)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class SharedSupplier < ApplicationRecord
|
||||
|
||||
# connect to database from sharedLists-Application
|
||||
SharedSupplier.establish_connection(FoodsoftConfig[:shared_lists])
|
||||
# set correct table_name in external DB
|
||||
|
|
@ -8,7 +7,6 @@ class SharedSupplier < ApplicationRecord
|
|||
has_many :suppliers, -> { undeleted }
|
||||
has_many :shared_articles, :foreign_key => :supplier_id
|
||||
|
||||
|
||||
def find_article_by_number(order_number)
|
||||
# note that `shared_articles` uses number instead order_number
|
||||
cached_articles.detect { |a| a.number == order_number }
|
||||
|
|
@ -22,7 +20,7 @@ class SharedSupplier < ApplicationRecord
|
|||
# when created by import from shared supplier feature.
|
||||
def autofill_attributes
|
||||
whitelist = %w(name address phone fax email url delivery_days note)
|
||||
attributes.select { |k,_v| whitelist.include?(k) }
|
||||
attributes.select { |k, _v| whitelist.include?(k) }
|
||||
end
|
||||
|
||||
# return list of synchronisation methods available for this supplier
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
# encoding: utf-8
|
||||
class StockArticle < Article
|
||||
|
||||
has_many :stock_changes
|
||||
|
||||
scope :available, -> { undeleted.where('quantity > 0') }
|
||||
|
||||
validates :quantity, presence: true, numericality: {greater_than_or_equal_to: 0}
|
||||
validates :quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
||||
|
||||
before_destroy :check_quantity
|
||||
|
||||
|
|
@ -30,12 +28,12 @@ class StockArticle < Article
|
|||
end
|
||||
|
||||
def quantity_ordered
|
||||
OrderArticle.where(article_id: id).
|
||||
joins(:order).where(orders: {state: %w[open finished received]}).sum(:units_to_order)
|
||||
OrderArticle.where(article_id: id)
|
||||
.joins(:order).where(orders: { state: %w[open finished received] }).sum(:units_to_order)
|
||||
end
|
||||
|
||||
def quantity_history
|
||||
stock_changes.reorder('stock_changes.created_at ASC').map{|s| s.quantity}.cumulative_sum
|
||||
stock_changes.reorder('stock_changes.created_at ASC').map { |s| s.quantity }.cumulative_sum
|
||||
end
|
||||
|
||||
def self.stock_value
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
class StockEvent < ApplicationRecord
|
||||
|
||||
has_many :stock_changes, dependent: :destroy
|
||||
has_many :stock_articles, through: :stock_changes
|
||||
|
||||
validates_presence_of :date
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# encoding: utf-8
|
||||
class Supplier < ApplicationRecord
|
||||
include MarkAsDeletedWithName
|
||||
include CustomFields
|
||||
|
|
@ -9,7 +8,7 @@ class Supplier < ApplicationRecord
|
|||
has_many :deliveries
|
||||
has_many :invoices
|
||||
belongs_to :supplier_category
|
||||
belongs_to :shared_supplier, optional: true # for the sharedLists-App
|
||||
belongs_to :shared_supplier, optional: true # for the sharedLists-App
|
||||
|
||||
validates :name, :presence => true, :length => { :in => 4..30 }
|
||||
validates :phone, :presence => true, :length => { :in => 8..25 }
|
||||
|
|
@ -65,7 +64,7 @@ class Supplier < ApplicationRecord
|
|||
.find_each { |new_shared_article| new_articles << new_shared_article.build_new_article(self) }
|
||||
# make them unavailable when desired
|
||||
if shared_sync_method == 'all_unavailable'
|
||||
new_articles.each {|new_article| new_article.availability = false }
|
||||
new_articles.each { |new_article| new_article.availability = false }
|
||||
end
|
||||
end
|
||||
return [updated_article_pairs, outlisted_articles, new_articles]
|
||||
|
|
@ -77,7 +76,7 @@ class Supplier < ApplicationRecord
|
|||
# @param options [Hash] Options passed to {FoodsoftFile#parse} except when listed here.
|
||||
# @option options [Boolean] :outlist_absent Set to +true+ to remove articles not in spreadsheet.
|
||||
# @option options [Boolean] :convert_units Omit or set to +true+ to keep current units, recomputing unit quantity and price.
|
||||
def sync_from_file(file, options={})
|
||||
def sync_from_file(file, options = {})
|
||||
all_order_numbers = []
|
||||
updated_article_pairs, outlisted_articles, new_articles = [], [], []
|
||||
FoodsoftFile::parse file, options do |status, new_attrs, line|
|
||||
|
|
@ -108,7 +107,7 @@ class Supplier < ApplicationRecord
|
|||
all_order_numbers << article.order_number if article
|
||||
end
|
||||
if options[:outlist_absent]
|
||||
outlisted_articles += articles.undeleted.where.not(order_number: all_order_numbers+[nil])
|
||||
outlisted_articles += articles.undeleted.where.not(order_number: all_order_numbers + [nil])
|
||||
end
|
||||
return [updated_article_pairs, outlisted_articles, new_articles]
|
||||
end
|
||||
|
|
@ -116,6 +115,7 @@ class Supplier < ApplicationRecord
|
|||
# default value
|
||||
def shared_sync_method
|
||||
return unless shared_supplier
|
||||
|
||||
self[:shared_sync_method] || 'import'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class SupplierCategory < ActiveRecord::Base
|
||||
|
||||
belongs_to :financial_transaction_class
|
||||
has_many :suppliers
|
||||
|
||||
|
|
@ -15,5 +14,4 @@ class SupplierCategory < ActiveRecord::Base
|
|||
def check_for_associated_suppliers
|
||||
raise I18n.t('activerecord.errors.has_many_left', collection: Supplier.model_name.human) if suppliers.undeleted.any?
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
class Task < ApplicationRecord
|
||||
has_many :assignments, :dependent => :destroy
|
||||
has_many :users, :through => :assignments
|
||||
|
|
@ -25,19 +24,18 @@ class Task < ApplicationRecord
|
|||
# Find all tasks, for which the current user should be responsible
|
||||
# but which aren't accepted yet
|
||||
def self.unaccepted_tasks_for(user)
|
||||
user.tasks.undone.where(assignments: {accepted: false})
|
||||
user.tasks.undone.where(assignments: { accepted: false })
|
||||
end
|
||||
|
||||
# Find all accepted tasks, which aren't done
|
||||
def self.accepted_tasks_for(user)
|
||||
user.tasks.undone.where(assignments: {accepted: true})
|
||||
user.tasks.undone.where(assignments: { accepted: true })
|
||||
end
|
||||
|
||||
|
||||
# find all tasks in the period (or another number of days)
|
||||
def self.next_assigned_tasks_for(user, number = FoodsoftConfig[:tasks_period_days].to_i)
|
||||
user.tasks.undone.where(assignments: {accepted: true}).
|
||||
where(["tasks.due_date >= ? AND tasks.due_date <= ?", Time.now, number.days.from_now])
|
||||
user.tasks.undone.where(assignments: { accepted: true })
|
||||
.where(["tasks.due_date >= ? AND tasks.due_date <= ?", Time.now, number.days.from_now])
|
||||
end
|
||||
|
||||
# count tasks with not enough responsible people
|
||||
|
|
@ -45,7 +43,7 @@ class Task < ApplicationRecord
|
|||
def self.unassigned_tasks_for(user)
|
||||
undone.includes(:assignments, workgroup: :memberships).select do |task|
|
||||
!task.enough_users_assigned? and
|
||||
(!task.workgroup or task.workgroup.memberships.detect { |m| m.user_id == user.id })
|
||||
(!task.workgroup or task.workgroup.memberships.detect { |m| m.user_id == user.id })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -53,6 +51,7 @@ class Task < ApplicationRecord
|
|||
periodic_task_group_count = {}
|
||||
self.unassigned_tasks_for(user).reject do |item|
|
||||
next false unless item.periodic_task_group
|
||||
|
||||
count = periodic_task_group_count[item.periodic_task_group] || 0
|
||||
periodic_task_group_count[item.periodic_task_group] = count + 1
|
||||
count >= max
|
||||
|
|
@ -64,11 +63,11 @@ class Task < ApplicationRecord
|
|||
end
|
||||
|
||||
def is_assigned?(user)
|
||||
self.assignments.detect {|ass| ass.user_id == user.id }
|
||||
self.assignments.detect { |ass| ass.user_id == user.id }
|
||||
end
|
||||
|
||||
def is_accepted?(user)
|
||||
self.assignments.detect {|ass| ass.user_id == user.id && ass.accepted }
|
||||
self.assignments.detect { |ass| ass.user_id == user.id && ass.accepted }
|
||||
end
|
||||
|
||||
def enough_users_assigned?
|
||||
|
|
@ -98,7 +97,7 @@ class Task < ApplicationRecord
|
|||
if user.blank?
|
||||
errors.add(:user_list)
|
||||
else
|
||||
if id == current_user_id.to_i
|
||||
if id == current_user_id.to_i
|
||||
# current_user will accept, when he puts himself to the list of users
|
||||
self.assignments.build :user => user, :accepted => true
|
||||
else
|
||||
|
|
@ -115,7 +114,7 @@ class Task < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_ordergroup_stats(user_ids = self.user_ids)
|
||||
Ordergroup.joins(:users).where(users: {id: user_ids}).each(&:update_stats!)
|
||||
Ordergroup.joins(:users).where(users: { id: user_ids }).each(&:update_stats!)
|
||||
end
|
||||
|
||||
def exclude_from_periodic_task_group
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'digest/sha1'
|
||||
# specific user rights through memberships (see Group)
|
||||
class User < ApplicationRecord
|
||||
include CustomFields
|
||||
#TODO: acts_as_paraniod ??
|
||||
# TODO: acts_as_paraniod ??
|
||||
|
||||
has_many :memberships, :dependent => :destroy
|
||||
has_many :groups, :through => :memberships
|
||||
#has_one :ordergroup, :through => :memberships, :source => :group, :class_name => "Ordergroup"
|
||||
# has_one :ordergroup, :through => :memberships, :source => :group, :class_name => "Ordergroup"
|
||||
def ordergroup
|
||||
Ordergroup.joins(:memberships).where(memberships: {user_id: self.id}).first
|
||||
Ordergroup.joins(:memberships).where(memberships: { user_id: self.id }).first
|
||||
end
|
||||
|
||||
has_many :workgroups, :through => :memberships, :source => :group, :class_name => "Workgroup"
|
||||
|
|
@ -49,7 +47,7 @@ class User < ApplicationRecord
|
|||
after_initialize do
|
||||
settings.defaults['profile'] = { 'language' => I18n.default_locale } unless settings.profile
|
||||
settings.defaults['messages'] = { 'send_as_email' => true } unless settings.messages
|
||||
settings.defaults['notify'] = { 'upcoming_tasks' => true } unless settings.notify
|
||||
settings.defaults['notify'] = { 'upcoming_tasks' => true } unless settings.notify
|
||||
end
|
||||
|
||||
before_save do
|
||||
|
|
@ -63,18 +61,18 @@ class User < ApplicationRecord
|
|||
settings_attributes.each do |key, value|
|
||||
value.each do |k, v|
|
||||
case v
|
||||
when '1'
|
||||
value[k] = true
|
||||
when '0'
|
||||
value[k] = false
|
||||
when '1'
|
||||
value[k] = true
|
||||
when '0'
|
||||
value[k] = false
|
||||
end
|
||||
end
|
||||
self.settings.merge!(key, value)
|
||||
end if settings_attributes
|
||||
|
||||
if ActiveModel::Type::Boolean.new.cast(create_ordergroup)
|
||||
og = Ordergroup.new({name: name})
|
||||
og.memberships.build({user: self})
|
||||
og = Ordergroup.new({ name: name })
|
||||
og.memberships.build({ user: self })
|
||||
og.save!
|
||||
end
|
||||
|
||||
|
|
@ -103,7 +101,7 @@ class User < ApplicationRecord
|
|||
match_nick = users[:nick].matches("%#{q}%")
|
||||
# or each word matches either first or last name
|
||||
match_name = q.split.map do |a|
|
||||
users[:first_name].matches("%#{a}%").or users[:last_name].matches("%#{a}%")
|
||||
users[:first_name].matches("%#{a}%").or users[:last_name].matches("%#{a}%")
|
||||
end.reduce(:and)
|
||||
User.where(match_nick.or match_name)
|
||||
end
|
||||
|
|
@ -123,7 +121,7 @@ class User < ApplicationRecord
|
|||
# Sets the user's password. It will be stored encrypted along with a random salt.
|
||||
def set_password
|
||||
unless password.blank?
|
||||
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
|
||||
salt = [Array.new(6) { rand(256).chr }.join].pack("m").chomp
|
||||
self.password_hash, self.password_salt = Digest::SHA1.hexdigest(password + salt), salt
|
||||
end
|
||||
end
|
||||
|
|
@ -161,37 +159,37 @@ class User < ApplicationRecord
|
|||
|
||||
# Checks the admin role
|
||||
def role_admin?
|
||||
groups.detect {|group| group.role_admin?}
|
||||
groups.detect { |group| group.role_admin? }
|
||||
end
|
||||
|
||||
# Checks the finance role
|
||||
def role_finance?
|
||||
FoodsoftConfig[:default_role_finance] || groups.detect {|group| group.role_finance?}
|
||||
FoodsoftConfig[:default_role_finance] || groups.detect { |group| group.role_finance? }
|
||||
end
|
||||
|
||||
# Checks the invoices role
|
||||
def role_invoices?
|
||||
FoodsoftConfig[:default_role_invoices] || groups.detect {|group| group.role_invoices?}
|
||||
FoodsoftConfig[:default_role_invoices] || groups.detect { |group| group.role_invoices? }
|
||||
end
|
||||
|
||||
# Checks the article_meta role
|
||||
def role_article_meta?
|
||||
FoodsoftConfig[:default_role_article_meta] || groups.detect {|group| group.role_article_meta?}
|
||||
FoodsoftConfig[:default_role_article_meta] || groups.detect { |group| group.role_article_meta? }
|
||||
end
|
||||
|
||||
# Checks the suppliers role
|
||||
def role_suppliers?
|
||||
FoodsoftConfig[:default_role_suppliers] || groups.detect {|group| group.role_suppliers?}
|
||||
FoodsoftConfig[:default_role_suppliers] || groups.detect { |group| group.role_suppliers? }
|
||||
end
|
||||
|
||||
# Checks the invoices role
|
||||
def role_pickups?
|
||||
FoodsoftConfig[:default_role_pickups] || groups.detect {|group| group.role_pickups?}
|
||||
FoodsoftConfig[:default_role_pickups] || groups.detect { |group| group.role_pickups? }
|
||||
end
|
||||
|
||||
# Checks the orders role
|
||||
def role_orders?
|
||||
FoodsoftConfig[:default_role_orders] || groups.detect {|group| group.role_orders?}
|
||||
FoodsoftConfig[:default_role_orders] || groups.detect { |group| group.role_orders? }
|
||||
end
|
||||
|
||||
def ordergroup_name
|
||||
|
|
@ -203,9 +201,9 @@ class User < ApplicationRecord
|
|||
group.users.exists?(self.id)
|
||||
end
|
||||
|
||||
#Returns an array with the users groups (but without the Ordergroups -> because tpye=>"")
|
||||
# Returns an array with the users groups (but without the Ordergroups -> because tpye=>"")
|
||||
def member_of_groups()
|
||||
self.groups.where(type: '')
|
||||
self.groups.where(type: '')
|
||||
end
|
||||
|
||||
def deleted?
|
||||
|
|
@ -232,6 +230,7 @@ class User < ApplicationRecord
|
|||
def self.custom_fields
|
||||
fields = FoodsoftConfig[:custom_fields] && FoodsoftConfig[:custom_fields][:user]
|
||||
return [] unless fields
|
||||
|
||||
fields.map(&:deep_symbolize_keys)
|
||||
end
|
||||
|
||||
|
|
@ -249,7 +248,6 @@ class User < ApplicationRecord
|
|||
def token_attributes
|
||||
# would be sensible to match ApplicationController#show_user
|
||||
# this should not be part of the model anyway
|
||||
{:id => id, :name => "#{display} (#{ordergroup.try(:name)})"}
|
||||
{ :id => id, :name => "#{display} (#{ordergroup.try(:name)})" }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# encoding: utf-8
|
||||
class Workgroup < Group
|
||||
include CustomFields
|
||||
|
||||
|
|
@ -26,5 +25,4 @@ class Workgroup < Group
|
|||
errors.add(:role_admin, I18n.t('workgroups.error_last_admin_role'))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue