12_generate_custom_csv_file #58
26 changed files with 75 additions and 78 deletions
|
@ -14,23 +14,23 @@ class AppleBar
|
||||||
def group_bar_state
|
def group_bar_state
|
||||||
if apples >= 100
|
if apples >= 100
|
||||||
'success'
|
'success'
|
||||||
|
elsif FoodsoftConfig[:stop_ordering_under].present? &&
|
||||||
|
(apples >= FoodsoftConfig[:stop_ordering_under])
|
||||||
|
'warning'
|
||||||
else
|
else
|
||||||
if FoodsoftConfig[:stop_ordering_under].present? and
|
'danger'
|
||||||
apples >= FoodsoftConfig[:stop_ordering_under]
|
|
||||||
'warning'
|
|
||||||
else
|
|
||||||
'danger'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Use apples as percentage, but show at least 10 percent
|
# Use apples as percentage, but show at least 10 percent
|
||||||
def group_bar_width
|
def group_bar_width
|
||||||
@ordergroup.apples < 2 ? 2 : @ordergroup.apples
|
[@ordergroup.apples, 2].max
|
||||||
end
|
end
|
||||||
|
|
||||||
def mean_order_amount_per_job
|
def mean_order_amount_per_job
|
||||||
(1 / @global_avg).round rescue 0
|
(1 / @global_avg).round
|
||||||
|
rescue
|
||||||
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
def apples
|
def apples
|
|
@ -16,7 +16,7 @@ class ArticlesCsv < RenderCSV
|
||||||
Article.human_attribute_name(:unit_quantity),
|
Article.human_attribute_name(:unit_quantity),
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
Article.human_attribute_name(:article_category),
|
Article.human_attribute_name(:article_category)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class ArticlesCsv < RenderCSV
|
||||||
o.unit_quantity,
|
o.unit_quantity,
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
o.article_category.try(:name),
|
o.article_category.try(:name)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -8,9 +8,7 @@ class BankAccountConnector
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def text
|
attr_reader :text
|
||||||
@text
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class TextField
|
class TextField
|
||||||
|
@ -24,13 +22,7 @@ class BankAccountConnector
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def name
|
attr_reader :name, :value
|
||||||
@name
|
|
||||||
end
|
|
||||||
|
|
||||||
def value
|
|
||||||
@value
|
|
||||||
end
|
|
||||||
|
|
||||||
def label
|
def label
|
||||||
@label || @name.to_s
|
@label || @name.to_s
|
||||||
|
@ -73,17 +65,7 @@ class BankAccountConnector
|
||||||
@bank_account.iban
|
@bank_account.iban
|
||||||
end
|
end
|
||||||
|
|
||||||
def auto_submit
|
attr_reader :auto_submit, :controls, :count
|
||||||
@auto_submit
|
|
||||||
end
|
|
||||||
|
|
||||||
def controls
|
|
||||||
@controls
|
|
||||||
end
|
|
||||||
|
|
||||||
def count
|
|
||||||
@count
|
|
||||||
end
|
|
||||||
|
|
||||||
def text(data)
|
def text(data)
|
||||||
@controls += [TextItem.new(data)]
|
@controls += [TextItem.new(data)]
|
||||||
|
@ -142,11 +124,9 @@ class BankAccountConnector
|
||||||
@bank_account.save!
|
@bank_account.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def load(data)
|
def load(data); end
|
||||||
end
|
|
||||||
|
|
||||||
def dump
|
def dump; end
|
||||||
end
|
|
||||||
|
|
||||||
def t(key, args = {})
|
def t(key, args = {})
|
||||||
return t(".fields.#{key}") unless key.is_a? String
|
return t(".fields.#{key}") unless key.is_a? String
|
|
@ -1,7 +1,7 @@
|
||||||
class BankTransactionReference
|
class BankTransactionReference
|
||||||
# parses a string from a bank transaction field
|
# parses a string from a bank transaction field
|
||||||
def self.parse(data)
|
def self.parse(data)
|
||||||
m = /(^|[^\w\.])FS(?<group>\d+)(\.(?<user>\d+))?(?<parts>([A-Za-z]+\d+(\.\d+)?)+)([^\w\.]|$)/.match(data)
|
m = /(^|[^\w.])FS(?<group>\d+)(\.(?<user>\d+))?(?<parts>([A-Za-z]+\d+(\.\d+)?)+)([^\w.]|$)/.match(data)
|
||||||
return unless m
|
return unless m
|
||||||
|
|
||||||
parts = {}
|
parts = {}
|
||||||
|
@ -13,7 +13,7 @@ class BankTransactionReference
|
||||||
|
|
||||||
ret = { group: m[:group].to_i, parts: parts }
|
ret = { group: m[:group].to_i, parts: parts }
|
||||||
ret[:user] = m[:user].to_i if m[:user]
|
ret[:user] = m[:user].to_i if m[:user]
|
||||||
return ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.js_code_for_user(user)
|
def self.js_code_for_user(user)
|
|
@ -27,12 +27,20 @@ module DateTimeAttributeValidate
|
||||||
define_method("#{attribute}_date_value=") do |val|
|
define_method("#{attribute}_date_value=") do |val|
|
||||||
self.instance_variable_set("@#{attribute}_is_set", true)
|
self.instance_variable_set("@#{attribute}_is_set", true)
|
||||||
self.instance_variable_set("@#{attribute}_date_value", val)
|
self.instance_variable_set("@#{attribute}_date_value", val)
|
||||||
self.send("#{attribute}_date=", val) rescue nil
|
begin
|
||||||
|
self.send("#{attribute}_date=", val)
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
define_method("#{attribute}_time_value=") do |val|
|
define_method("#{attribute}_time_value=") do |val|
|
||||||
self.instance_variable_set("@#{attribute}_is_set", true)
|
self.instance_variable_set("@#{attribute}_is_set", true)
|
||||||
self.instance_variable_set("@#{attribute}_time_value", val)
|
self.instance_variable_set("@#{attribute}_time_value", val)
|
||||||
self.send("#{attribute}_time=", val) rescue nil
|
begin
|
||||||
|
self.send("#{attribute}_time=", val)
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# fallback to field when values are not set
|
# fallback to field when values are not set
|
||||||
|
@ -48,11 +56,19 @@ module DateTimeAttributeValidate
|
||||||
# validate date and time
|
# validate date and time
|
||||||
define_method("#{attribute}_datetime_value_valid") do
|
define_method("#{attribute}_datetime_value_valid") do
|
||||||
date = self.instance_variable_get("@#{attribute}_date_value")
|
date = self.instance_variable_get("@#{attribute}_date_value")
|
||||||
unless date.blank? || (Date.parse(date) rescue nil)
|
unless date.blank? || begin
|
||||||
|
Date.parse(date)
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
errors.add(attribute, "is not a valid date") # @todo I18n
|
errors.add(attribute, "is not a valid date") # @todo I18n
|
||||||
end
|
end
|
||||||
time = self.instance_variable_get("@#{attribute}_time_value")
|
time = self.instance_variable_get("@#{attribute}_time_value")
|
||||||
unless time.blank? || (Time.parse(time) rescue nil)
|
unless time.blank? || begin
|
||||||
|
Time.parse(time)
|
||||||
|
rescue
|
||||||
|
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
|
end
|
|
@ -54,8 +54,8 @@ module Foodsoft
|
||||||
# @param options [Hash<String, String>] Extra variables to expand
|
# @param options [Hash<String, String>] Extra variables to expand
|
||||||
# @return [String] Expanded string
|
# @return [String] Expanded string
|
||||||
def self.expand(str, options = {})
|
def self.expand(str, options = {})
|
||||||
str.gsub /{{([._a-zA-Z0-9]+)}}/ do
|
str.gsub(/{{([._a-zA-Z0-9]+)}}/) do
|
||||||
options[$1] || self.get($1)
|
options[::Regexp.last_match(1)] || self.get(::Regexp.last_match(1))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,6 +44,8 @@ class FoodsoftConfig
|
||||||
# @return [ActiveSupport::HashWithIndifferentAccess] Current configuration from configuration file.
|
# @return [ActiveSupport::HashWithIndifferentAccess] Current configuration from configuration file.
|
||||||
mattr_accessor :config
|
mattr_accessor :config
|
||||||
|
|
||||||
|
mattr_accessor :default_config
|
||||||
|
|
||||||
# Configuration file location.
|
# Configuration file location.
|
||||||
# Taken from environment variable +FOODSOFT_APP_CONFIG+,
|
# Taken from environment variable +FOODSOFT_APP_CONFIG+,
|
||||||
# or else +config/app_config.yml+.
|
# or else +config/app_config.yml+.
|
||||||
|
@ -189,7 +191,7 @@ class FoodsoftConfig
|
||||||
|
|
||||||
# @return [Hash] Full configuration.
|
# @return [Hash] Full configuration.
|
||||||
def to_hash
|
def to_hash
|
||||||
keys.to_h { |k| [k, self[k]] }
|
keys.index_with { |k| self[k] }
|
||||||
end
|
end
|
||||||
|
|
||||||
# for using active_model_serializer in the api/v1/configs controller
|
# for using active_model_serializer in the api/v1/configs controller
|
||||||
|
@ -216,7 +218,6 @@ class FoodsoftConfig
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# @return [Hash] Default configuration values
|
# @return [Hash] Default configuration values
|
||||||
mattr_accessor :default_config
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -6,7 +6,11 @@ module FoodsoftDateUtil
|
||||||
schedule = IceCube::Schedule.new(start)
|
schedule = IceCube::Schedule.new(start)
|
||||||
schedule.add_recurrence_rule rule_from(options[:recurr])
|
schedule.add_recurrence_rule rule_from(options[:recurr])
|
||||||
# @todo handle ical parse errors
|
# @todo handle ical parse errors
|
||||||
occ = (schedule.next_occurrence(from).to_time rescue nil)
|
occ = begin
|
||||||
|
schedule.next_occurrence(from).to_time
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if options && options[:time] && occ
|
if options && options[:time] && occ
|
||||||
occ = occ.beginning_of_day.advance(seconds: Time.parse(options[:time]).seconds_since_midnight)
|
occ = occ.beginning_of_day.advance(seconds: Time.parse(options[:time]).seconds_since_midnight)
|
||||||
|
@ -17,9 +21,10 @@ module FoodsoftDateUtil
|
||||||
# @param p [String, Symbol, Hash, IceCube::Rule] What to return a rule from.
|
# @param p [String, Symbol, Hash, IceCube::Rule] What to return a rule from.
|
||||||
# @return [IceCube::Rule] Recurring rule
|
# @return [IceCube::Rule] Recurring rule
|
||||||
def self.rule_from(p)
|
def self.rule_from(p)
|
||||||
if p.is_a? String
|
case p
|
||||||
|
when String
|
||||||
IceCube::Rule.from_ical(p)
|
IceCube::Rule.from_ical(p)
|
||||||
elsif p.is_a? Hash
|
when Hash
|
||||||
IceCube::Rule.from_hash(p)
|
IceCube::Rule.from_hash(p)
|
||||||
else
|
else
|
||||||
p
|
p
|
|
@ -19,7 +19,7 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def on_rcpt_to_event(ctx, rcpt_to)
|
def on_rcpt_to_event(_ctx, rcpt_to)
|
||||||
recipient = rcpt_to.gsub(/^\s*<\s*(.*)\s*>\s*$/, '\1')
|
recipient = rcpt_to.gsub(/^\s*<\s*(.*)\s*>\s*$/, '\1')
|
||||||
@handlers << self.class.find_handler(recipient)
|
@handlers << self.class.find_handler(recipient)
|
||||||
rcpt_to
|
rcpt_to
|
||||||
|
@ -29,20 +29,18 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_message_data_event(ctx)
|
def on_message_data_event(ctx)
|
||||||
begin
|
@handlers.each do |handler|
|
||||||
@handlers.each do |handler|
|
handler.call(ctx[:message][:data])
|
||||||
handler.call(ctx[:message][:data])
|
|
||||||
end
|
|
||||||
rescue => error
|
|
||||||
ExceptionNotifier.notify_exception(error, data: ctx)
|
|
||||||
raise error
|
|
||||||
ensure
|
|
||||||
@handlers.clear
|
|
||||||
end
|
end
|
||||||
|
rescue => error
|
||||||
|
ExceptionNotifier.notify_exception(error, data: ctx)
|
||||||
|
raise error
|
||||||
|
ensure
|
||||||
|
@handlers.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.find_handler(recipient)
|
def self.find_handler(recipient)
|
||||||
m = /(?<foodcoop>[^@\.]+)\.(?<address>[^@]+)(@(?<hostname>[^@]+))?/.match 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]
|
raise "Foodcoop '#{m[:foodcoop]}' could not be found" unless FoodsoftConfig.allowed_foodcoop? m[:foodcoop]
|
||||||
|
|
||||||
|
@ -51,7 +49,7 @@ class FoodsoftMailReceiver < MidiSmtpServer::Smtpd
|
||||||
@@registered_classes.each do |klass|
|
@@registered_classes.each do |klass|
|
||||||
if match = klass.regexp.match(m[:address])
|
if match = klass.regexp.match(m[:address])
|
||||||
handler = klass.new match
|
handler = klass.new match
|
||||||
return lambda { |data| handler.received(data) }
|
return ->(data) { handler.received(data) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,7 +32,7 @@ class InvoicesCsv < RenderCSV
|
||||||
t.deposit,
|
t.deposit,
|
||||||
t.deposit_credit,
|
t.deposit_credit,
|
||||||
t.paid_on,
|
t.paid_on,
|
||||||
t.note,
|
t.note
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,4 +1,4 @@
|
||||||
class OrderPdf < RenderPDF
|
class OrderPDF < RenderPDF
|
||||||
attr_reader :order
|
attr_reader :order
|
||||||
|
|
||||||
def initialize(order, options = {})
|
def initialize(order, options = {})
|
||||||
|
@ -55,7 +55,7 @@ class OrderPdf < RenderPDF
|
||||||
end
|
end
|
||||||
|
|
||||||
def group_order_article_quantity_with_tolerance(goa)
|
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
|
end
|
||||||
|
|
||||||
def group_order_article_result(goa)
|
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)')
|
.pluck('groups.name', 'SUM(group_orders.price)', 'ordergroup_id', 'SUM(group_orders.transport)')
|
||||||
|
|
||||||
result.map do |item|
|
result.map do |item|
|
||||||
[item.first || stock_ordergroup_name] + item[1..-1]
|
[item.first || stock_ordergroup_name] + item[1..]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class OrderPdf < RenderPDF
|
||||||
def each_ordergroup_batch(batch_size)
|
def each_ordergroup_batch(batch_size)
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
||||||
while true
|
loop do
|
||||||
go_records = ordergroups(offset, batch_size)
|
go_records = ordergroups(offset, batch_size)
|
||||||
|
|
||||||
break unless go_records.any?
|
break unless go_records.any?
|
|
@ -1,5 +1,5 @@
|
||||||
class OrderTxt
|
class OrderTxt
|
||||||
def initialize(order, options = {})
|
def initialize(order, _options = {})
|
||||||
@order = order
|
@order = order
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,10 +15,10 @@ class OrderTxt
|
||||||
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 += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n"
|
||||||
text += "****** " + I18n.t('orders.fax.articles') + "\n\n"
|
text += "****** " + I18n.t('orders.fax.articles') + "\n\n"
|
||||||
text += "%8s %8s %s\n" % [I18n.t('orders.fax.number'), I18n.t('orders.fax.amount'), I18n.t('orders.fax.name')]
|
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
|
# now display all ordered articles
|
||||||
@order.order_articles.ordered.includes([:article, :article_price]).each do |oa|
|
@order.order_articles.ordered.includes([:article, :article_price]).each do |oa|
|
||||||
text += "%8s %8d %s\n" % [oa.article.order_number, oa.units_to_order.to_i, oa.article.name]
|
text += format("%8s %8d %s\n", oa.article.order_number, oa.units_to_order.to_i, oa.article.name)
|
||||||
end
|
end
|
||||||
text
|
text
|
||||||
end
|
end
|
|
@ -14,9 +14,9 @@ class OrdergroupsCsv < RenderCSV
|
||||||
Ordergroup.human_attribute_name(:break_start),
|
Ordergroup.human_attribute_name(:break_start),
|
||||||
Ordergroup.human_attribute_name(:break_end),
|
Ordergroup.human_attribute_name(:break_end),
|
||||||
Ordergroup.human_attribute_name(:last_user_activity),
|
Ordergroup.human_attribute_name(:last_user_activity),
|
||||||
Ordergroup.human_attribute_name(:last_order),
|
Ordergroup.human_attribute_name(:last_order)
|
||||||
]
|
]
|
||||||
row + Ordergroup.custom_fields.map { |f| f[:label] }
|
row + Ordergroup.custom_fields.pluck(:label)
|
||||||
end
|
end
|
||||||
|
|
||||||
def data
|
def data
|
||||||
|
@ -33,7 +33,7 @@ class OrdergroupsCsv < RenderCSV
|
||||||
o.break_start,
|
o.break_start,
|
||||||
o.break_end,
|
o.break_end,
|
||||||
o.last_user_activity,
|
o.last_user_activity,
|
||||||
o.last_order.try(:starts),
|
o.last_order.try(:starts)
|
||||||
]
|
]
|
||||||
yield row + Ordergroup.custom_fields.map { |f| o.settings.custom_fields[f[:name]] }
|
yield row + Ordergroup.custom_fields.map { |f| o.settings.custom_fields[f[:name]] }
|
||||||
end
|
end
|
|
@ -18,7 +18,7 @@ class RotatedCell < Prawn::Table::Cell::Text
|
||||||
(height + (border_top_width / 2.0) + (border_bottom_width / 2.0)) / tan_rotation
|
(height + (border_top_width / 2.0) + (border_bottom_width / 2.0)) / tan_rotation
|
||||||
end
|
end
|
||||||
|
|
||||||
def styled_width_of(text)
|
def styled_width_of(_text)
|
||||||
options = @text_options.reject { |k| k == :style }
|
options = @text_options.reject { |k| k == :style }
|
||||||
with_font { (@pdf.height_of(@content, options) + padding_top + padding_bottom) / tan_rotation }
|
with_font { (@pdf.height_of(@content, options) + padding_top + padding_bottom) / tan_rotation }
|
||||||
end
|
end
|
||||||
|
@ -156,9 +156,10 @@ class RenderPDF < Prawn::Document
|
||||||
def pdf_add_page_breaks?(docid = nil)
|
def pdf_add_page_breaks?(docid = nil)
|
||||||
docid ||= self.class.name.underscore
|
docid ||= self.class.name.underscore
|
||||||
cfg = FoodsoftConfig[:pdf_add_page_breaks]
|
cfg = FoodsoftConfig[:pdf_add_page_breaks]
|
||||||
if cfg.is_a? Array
|
case cfg
|
||||||
|
when Array
|
||||||
cfg.index(docid.to_s).any?
|
cfg.index(docid.to_s).any?
|
||||||
elsif cfg.is_a? Hash
|
when Hash
|
||||||
cfg[docid.to_s]
|
cfg[docid.to_s]
|
||||||
else
|
else
|
||||||
cfg
|
cfg
|
|
@ -21,8 +21,6 @@ class TokenVerifier < ActiveSupport::MessageVerifier
|
||||||
# return original message
|
# return original message
|
||||||
if r.length > 2
|
if r.length > 2
|
||||||
r[2]
|
r[2]
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,8 +30,6 @@ class TokenVerifier < ActiveSupport::MessageVerifier
|
||||||
|
|
||||||
class InvalidPrefix < ActiveSupport::MessageVerifier::InvalidSignature; end
|
class InvalidPrefix < ActiveSupport::MessageVerifier::InvalidSignature; end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def self.secret
|
def self.secret
|
||||||
# secret_key_base for Rails 4, but Rails 3 initializer may still be used
|
# secret_key_base for Rails 4, but Rails 3 initializer may still be used
|
||||||
Foodsoft::Application.config.secret_key_base || Foodsoft::Application.config.secret_token
|
Foodsoft::Application.config.secret_key_base || Foodsoft::Application.config.secret_token
|
Loading…
Reference in a new issue