Merge branch 'master' into updated-gems

This commit is contained in:
wvengen 2013-07-16 00:00:55 +02:00
commit 9fb6597980
38 changed files with 352 additions and 223 deletions

View file

@ -10,6 +10,7 @@ var groupBalance = 0; // available group money
var currencySeparator = "."; // default decimal separator var currencySeparator = "."; // default decimal separator
var currencyPrecision = 2; // default digits behind comma var currencyPrecision = 2; // default digits behind comma
var currencyUnit = "€"; // default currency var currencyUnit = "€"; // default currency
var minimumBalance = 0; // minimum group balance for the order to be succesful
var toleranceIsCostly = true; // default tolerance behaviour var toleranceIsCostly = true; // default tolerance behaviour
var isStockit = false; // Wheter the order is from stock oder normal supplier var isStockit = false; // Wheter the order is from stock oder normal supplier
@ -40,6 +41,10 @@ function setGroupBalance(amount) {
groupBalance = amount; groupBalance = amount;
} }
function setMinimumBalance(amount) {
minimumBalance = amount;
}
function addData(orderArticleId, itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated, available) { function addData(orderArticleId, itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated, available) {
var i = orderArticleId; var i = orderArticleId;
price[i] = itemPrice; price[i] = itemPrice;
@ -159,7 +164,7 @@ function updateBalance() {
$('#total_balance').val(asMoney(balance)); $('#total_balance').val(asMoney(balance));
// determine bgcolor and submit button state according to balance // determine bgcolor and submit button state according to balance
var bgcolor = ''; var bgcolor = '';
if (balance < 0) { if (balance < minimumBalance) {
bgcolor = '#FF0000'; bgcolor = '#FF0000';
$('#submit_button').attr('disabled', 'disabled') $('#submit_button').attr('disabled', 'disabled')
} else { } else {

View file

@ -55,4 +55,9 @@ class StockitController < ApplicationController
render :partial => 'form', :locals => {:stock_article => stock_article} render :partial => 'form', :locals => {:stock_article => stock_article}
end end
def history
@stock_article = StockArticle.undeleted.find(params[:stock_article_id])
@stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC').each {|s| s.readonly!}
end
end end

View file

@ -18,6 +18,9 @@ class TasksController < ApplicationController
def create def create
@task = Task.new(params[:task]) @task = Task.new(params[:task])
if params[:periodic]
@task.periodic_task_group = PeriodicTaskGroup.new
end
if @task.save if @task.save
redirect_to tasks_url, :notice => I18n.t('tasks.create.notice') redirect_to tasks_url, :notice => I18n.t('tasks.create.notice')
else else
@ -32,13 +35,20 @@ class TasksController < ApplicationController
def edit def edit
@task = Task.find(params[:id]) @task = Task.find(params[:id])
@task.current_user_id = current_user.id @task.current_user_id = current_user.id
if @task.periodic?
flash.now[:alert] = I18n.t('tasks.edit.warning_periodic').html_safe
end
end end
def update def update
@task = Task.find(params[:id]) @task = Task.find(params[:id])
was_periodic = @task.periodic?
@task.attributes=(params[:task]) @task.attributes=(params[:task])
if @task.errors.empty? && @task.save if @task.errors.empty? && @task.save
flash[:notice] = I18n.t('tasks.update.notice') flash[:notice] = I18n.t('tasks.update.notice')
if was_periodic and not @task.periodic?
flash[:notice] = I18n.t('tasks.update.notice_converted')
end
if @task.workgroup if @task.workgroup
redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id) redirect_to workgroup_tasks_url(workgroup_id: @task.workgroup_id)
else else
@ -53,7 +63,12 @@ class TasksController < ApplicationController
task = Task.find(params[:id]) task = Task.find(params[:id])
# Save user_ids to update apple statistics after destroy # Save user_ids to update apple statistics after destroy
user_ids = task.user_ids user_ids = task.user_ids
if params[:periodic]
task.periodic_task_group.exclude_tasks_before(task)
task.periodic_task_group.destroy
else
task.destroy task.destroy
end
task.update_ordergroup_stats(user_ids) 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')

View file

@ -4,7 +4,7 @@ module Finance::OrderArticlesHelper
if @order.stockit? if @order.stockit?
StockArticle.order('articles.name') StockArticle.order('articles.name')
else else
@order.supplier.articles.order('articles.name') @order.supplier.articles.undeleted.order('articles.name')
end end
end end
end end

View file

@ -4,4 +4,14 @@ module StockitHelper
class_names << "unavailable" if article.quantity_available <= 0 class_names << "unavailable" if article.quantity_available <= 0
class_names.join(" ") class_names.join(" ")
end end
def link_to_stock_change_reason(stock_change)
if stock_change.delivery_id
link_to t('.delivery'), supplier_delivery_path(stock_change.delivery.supplier, stock_change.delivery)
elsif stock_change.order_id
link_to t('.order'), order_path(stock_change.order)
elsif stock_change.stock_taking_id
link_to t('.stock_taking'), stock_taking_path(stock_change.stock_taking)
end
end
end end

View file

@ -108,10 +108,10 @@ class Ordergroup < Group
# Make sure, the name is uniq, add usefull message if uniq group is already deleted # Make sure, the name is uniq, add usefull message if uniq group is already deleted
def uniqueness_of_name def uniqueness_of_name
id = new_record? ? nil : self.id group = Ordergroup.where('groups.name = ?', name)
group = Ordergroup.where('groups.id != ? AND groups.name = ?', id, name).first group = group.where('groups.id != ?', self.id) unless new_record?
if group.present? if group.exists?
message = group.deleted? ? :taken_with_deleted : :taken message = group.first.deleted? ? :taken_with_deleted : :taken
errors.add :name, message errors.add :name, message
end end
end end

View file

@ -0,0 +1,29 @@
class PeriodicTaskGroup < ActiveRecord::Base
has_many :tasks, dependent: :destroy
PeriodDays = 7
def has_next_task?
return false if tasks.empty?
return false if tasks.first.due_date.nil?
return true
end
def create_next_task
template_task = tasks.first
self.next_task_date ||= template_task.due_date + PeriodDays
next_task = template_task.dup
next_task.due_date = next_task_date
next_task.save
self.next_task_date += PeriodDays
self.save
end
def exclude_tasks_before(task)
tasks.where("due_date < '#{task.due_date}'").each do |t|
t.update_attribute(:periodic_task_group, nil)
end
end
end

View file

@ -18,6 +18,10 @@ class StockArticle < Article
joins(:order).where("orders.state = 'open' OR orders.state = 'finished'").sum(:units_to_order) joins(:order).where("orders.state = 'open' OR orders.state = 'finished'").sum(:units_to_order)
end end
def quantity_history
stock_changes.reorder('stock_changes.created_at ASC').map{|s| s.quantity}.cumulative_sum
end
def self.stock_value def self.stock_value
available.collect { |a| a.quantity * a.gross_price }.sum available.collect { |a| a.quantity * a.gross_price }.sum
end end

View file

@ -1,6 +1,7 @@
class StockChange < ActiveRecord::Base class StockChange < ActiveRecord::Base
belongs_to :delivery belongs_to :delivery
belongs_to :order belongs_to :order
belongs_to :stock_taking
belongs_to :stock_article belongs_to :stock_article
validates_presence_of :stock_article_id, :quantity validates_presence_of :stock_article_id, :quantity

View file

@ -82,10 +82,10 @@ class Supplier < ActiveRecord::Base
# Make sure, the name is uniq, add usefull message if uniq group is already deleted # Make sure, the name is uniq, add usefull message if uniq group is already deleted
def uniqueness_of_name def uniqueness_of_name
id = new_record? ? nil : self.id supplier = Supplier.where('suppliers.name = ?', name)
supplier = Supplier.where('suppliers.id != ? AND suppliers.name = ?', id, name).first supplier = supplier.where('suppliers.id != ?', self.id) unless new_record?
if supplier.present? if supplier.exists?
message = supplier.deleted? ? :taken_with_deleted : :taken message = supplier.first.deleted? ? :taken_with_deleted : :taken
errors.add :name, message errors.add :name, message
end end
end end

View file

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
class Task < ActiveRecord::Base class Task < ActiveRecord::Base
has_many :assignments, :dependent => :destroy has_many :assignments, :dependent => :destroy
has_many :users, :through => :assignments has_many :users, :through => :assignments
belongs_to :workgroup belongs_to :workgroup
belongs_to :periodic_task_group
scope :non_group, where(workgroup_id: nil, done: false) scope :non_group, where(workgroup_id: nil, done: false)
scope :done, where(done: true) scope :done, where(done: true)
@ -16,7 +18,9 @@ class Task < ActiveRecord::Base
validates :required_users, :presence => true validates :required_users, :presence => true
validates_numericality_of :duration, :required_users, :only_integer => true, :greater_than => 0 validates_numericality_of :duration, :required_users, :only_integer => true, :greater_than => 0
validates_length_of :description, maximum: 250 validates_length_of :description, maximum: 250
validates :done, exclusion: { in: [true] }, if: :periodic?, on: :create
before_save :exclude_from_periodic_task_group, if: :changed?, unless: :new_record?
after_save :update_ordergroup_stats after_save :update_ordergroup_stats
# Find all tasks, for which the current user should be responsible # Find all tasks, for which the current user should be responsible
@ -46,6 +50,10 @@ class Task < ActiveRecord::Base
end end
end end
def periodic?
not periodic_task_group.nil?
end
def is_assigned?(user) def is_assigned?(user)
self.assignments.detect {|ass| ass.user_id == user.id } self.assignments.detect {|ass| ass.user_id == user.id }
end end
@ -100,5 +108,10 @@ class Task < ActiveRecord::Base
def update_ordergroup_stats(user_ids = self.user_ids) 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 end
def exclude_from_periodic_task_group
self.periodic_task_group = nil
true
end
end end

View file

@ -6,51 +6,9 @@ class Workgroup < Group
has_many :open_tasks, :class_name => 'Task', :conditions => ['done = ?', false], :order => 'due_date ASC' has_many :open_tasks, :class_name => 'Task', :conditions => ['done = ?', false], :order => 'due_date ASC'
validates_uniqueness_of :name validates_uniqueness_of :name
validates_presence_of :task_name, :weekday, :task_required_users, :next_weekly_tasks_number,
:if => :weekly_task
validates_numericality_of :next_weekly_tasks_number, :greater_than => 0, :less_than => 21, :only_integer => true,
:if => :weekly_task
validates_length_of :task_description, maximum: 250
validate :last_admin_on_earth, :on => :update validate :last_admin_on_earth, :on => :update
before_destroy :check_last_admin_group before_destroy :check_last_admin_group
def self.weekdays
days = I18n.t('date.day_names')
(0..days.length-1).map {|i| [days[i], i.to_s]}
end
# Returns an Array with date-objects to represent the next weekly-tasks
def next_weekly_tasks
# our system starts from 0 (sunday) to 6 (saturday)
# get difference between groups weekday and now
diff = self.weekday - Time.now.wday
if diff >= 0
# weektask is in current week
nextTask = diff.day.from_now
else
# weektask is in the next week
nextTask = (diff + 7).day.from_now
end
# now generate the Array
nextTasks = Array.new
next_weekly_tasks_number.times do
nextTasks << nextTask.to_date
nextTask = 1.week.from_now(nextTask)
end
return nextTasks
end
def task_attributes(date)
{
:name => task_name,
:description => task_description,
:due_date => date,
:required_users => task_required_users,
:duration => task_duration,
:weekly => true
}
end
protected protected
# Check before destroy a group, if this is the last group with admin role # Check before destroy a group, if this is the last group with admin role

View file

@ -4,6 +4,7 @@
#{data_to_js(@ordering_data)} #{data_to_js(@ordering_data)}
setGroupBalance(#{@ordering_data[:available_funds]}); setGroupBalance(#{@ordering_data[:available_funds]});
setCurrencyFormat("#{t('number.currency.format.separator')}", #{t('number.currency.format.precision')}, "#{t('number.currency.format.unit')}"); setCurrencyFormat("#{t('number.currency.format.separator')}", #{t('number.currency.format.precision')}, "#{t('number.currency.format.unit')}");
setMinimumBalance(#{FoodsoftConfig[:minimum_balance] or 0});
setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]}); setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
setStockit(#{@order.stockit?}); setStockit(#{@order.stockit?});
}); });

View file

@ -45,26 +45,6 @@
= f.label :role_orders = f.label :role_orders
%br/ %br/
= f.check_box :role_orders = f.check_box :role_orders
%p
= f.label :weekly_task
%br/
= f.check_box :weekly_task
%p
= f.label :weekday
%br/
= f.text_field :weekday
%p
= f.label :task_name
%br/
= f.text_field :task_name
%p
= f.label :task_description
%br/
= f.text_field :task_description
%p
= f.label :task_required_users
%br/
= f.text_field :task_required_users
%p %p
= f.label :deleted_at = f.label :deleted_at
%br/ %br/

View file

@ -12,11 +12,6 @@
%th Role Article Meta %th Role Article Meta
%th Role Finance %th Role Finance
%th Role Orders %th Role Orders
%th Weekly Task
%th Weekday
%th Task Name
%th Task Description
%th Task Required Users
%th Deleted At %th Deleted At
%th Contact Person %th Contact Person
%th Contact Phone %th Contact Phone
@ -34,11 +29,6 @@
%td= h ordergroup.role_article_meta %td= h ordergroup.role_article_meta
%td= h ordergroup.role_finance %td= h ordergroup.role_finance
%td= h ordergroup.role_orders %td= h ordergroup.role_orders
%td= h ordergroup.weekly_task
%td= h ordergroup.weekday
%td= h ordergroup.task_name
%td= h ordergroup.task_description
%td= h ordergroup.task_required_users
%td= h ordergroup.deleted_at %td= h ordergroup.deleted_at
%td= h ordergroup.contact_person %td= h ordergroup.contact_person
%td= h ordergroup.contact_phone %td= h ordergroup.contact_phone

View file

@ -29,7 +29,10 @@
- if order.stockit? - if order.stockit?
%td= units %td= units
- else - else
%td= "#{order_article.quantity} + #{order_article.tolerance}" if unit_quantity > 1 - if unit_quantity > 1 or order_article.tolerance > 0
%td= "#{order_article.quantity} + #{order_article.tolerance}"
- else
%td= "#{order_article.quantity}"
%td= units %td= units
%p %p
= t '.prices_sum' = t '.prices_sum'

View file

@ -13,13 +13,6 @@
- members = group.users - members = group.users
= "(#{members.size})" = "(#{members.size})"
= members.collect(&:nick).join(", ") = members.collect(&:nick).join(", ")
- if group.is_a?(Workgroup) - unless group.is_a?(Workgroup)
%dt= t('.weekly_job') + ':'
%dd
- if group.weekly_task
=h "#{group.task_name} am #{weekday(group.weekday)}"
- else
= t '.no_weekly_job'
- else
%dt= t '.apple_limit' %dt= t '.apple_limit'
%dd= group.ignore_apple_restriction ? t('.deactivated') : t('.activated') %dd= group.ignore_apple_restriction ? t('.deactivated') : t('.activated')

View file

@ -3,17 +3,6 @@
= yield = yield
- if f.object.is_a?(Workgroup)
%h3= t '.title'
= f.input :weekly_task
#weekly_task_fields
= f.input :weekday, as: :select, collection: Workgroup.weekdays
= f.input :task_name
= f.input :task_required_users
= f.input :task_duration, :as => :select, :collection => (1..3)
= f.input :task_description, as: :text, input_html: {rows: 5}
= f.input :next_weekly_tasks_number
= f.input :user_tokens, :as => :string, = f.input :user_tokens, :as => :string,
:input_html => { 'data-pre' => f.object.users.map { |u| u.token_attributes }.to_json } :input_html => { 'data-pre' => f.object.users.map { |u| u.token_attributes }.to_json }

View file

@ -0,0 +1,17 @@
- title t('.stock_changes', :article_name => @stock_article.name)
%table.table.table-hover#stock_changes
%thead
%tr
%th= t '.datetime'
%th= t '.reason'
%th= t '.change_quantity'
%th= t '.new_quantity'
%tbody
- reversed_history = @stock_article.quantity_history.reverse
- @stock_changes.each_with_index do |stock_change, index|
%tr
%td= l stock_change.created_at
%td= link_to_stock_change_reason(stock_change)
%td= stock_change.quantity
%td= reversed_history[index]

View file

@ -56,6 +56,7 @@
%td= article.article_category.name %td= article.article_category.name
%td %td
= link_to t('ui.edit'), edit_stock_article_path(article), class: 'btn btn-mini' = link_to t('ui.edit'), edit_stock_article_path(article), class: 'btn btn-mini'
= link_to t('ui.history'), stock_article_history_path(article), class: 'btn btn-mini'
= link_to t('ui.delete'), article, :method => :delete, :confirm => t('.confirm_delete'), = link_to t('ui.delete'), article, :method => :delete, :confirm => t('.confirm_delete'),
class: 'btn btn-mini btn-danger', :remote => true class: 'btn btn-mini btn-danger', :remote => true
%p %p

View file

@ -25,5 +25,7 @@
= f.input :due_date, as: :date_picker = f.input :due_date, as: :date_picker
= f.input :done = f.input :done
.form-actions .form-actions
= f.submit class: 'btn' = f.submit class: 'btn btn-primary'
- if @task.new_record?
= f.submit t('.submit.periodic'), name: 'periodic', class: 'btn'
= link_to t('ui.or_cancel'), :back = link_to t('ui.or_cancel'), :back

View file

@ -2,6 +2,7 @@
%thead %thead
%tr %tr
%th= t '.due_date' %th= t '.due_date'
%th
%th= t '.task' %th= t '.task'
%th{:colspan => '2'} %th{:colspan => '2'}
= t '.who' = t '.who'
@ -11,6 +12,9 @@
- done = task.done ? " done" : "" - done = task.done ? " done" : ""
%tr{:class => done } %tr{:class => done }
%td= format_date(task.due_date) unless task.due_date.nil? %td= format_date(task.due_date) unless task.due_date.nil?
%td
- if task.periodic?
%i.icon-repeat{title: t('tasks.repeated')}
%td= link_to t('.task_format', name: task.name, duration: task.duration), task_path(task) %td= link_to t('.task_format', name: task.name, duration: task.duration), task_path(task)
%td %td
= task_assignments task = task_assignments task

View file

@ -10,7 +10,10 @@
%dd= simple_format(@task.description) %dd= simple_format(@task.description)
- if @task.due_date.present? - if @task.due_date.present?
%dt= t '.due_date' %dt= t '.due_date'
%dd= format_date(@task.due_date) %dd
= format_date(@task.due_date)
- if @task.periodic?
%i.icon-repeat{title: t('tasks.repeated')}
%dt= t 'simple_form.labels.task.duration' %dt= t 'simple_form.labels.task.duration'
%dd= t('.hours', count: @task.duration) %dd= t('.hours', count: @task.duration)
%dt= t 'simple_form.labels.task.user_list' %dt= t 'simple_form.labels.task.user_list'
@ -29,3 +32,6 @@
= link_to t('ui.edit'), edit_task_path(@task), class: 'btn' = link_to t('ui.edit'), edit_task_path(@task), class: 'btn'
= link_to t('ui.delete'), task_path(@task), :method => :delete, :confirm => "Die Aufgabe wirklich löschen?", = link_to t('ui.delete'), task_path(@task), :method => :delete, :confirm => "Die Aufgabe wirklich löschen?",
class: 'btn btn-danger' class: 'btn btn-danger'
- if @task.periodic?
= link_to t('.delete_group'), task_path(@task, periodic: true), method: :delete,
confirm: t('.confirm_delete_group'), class: 'btn btn-danger'

View file

@ -1,16 +1,6 @@
- title t('.title', workgroup: @group.name) - title t('.title', workgroup: @group.name)
= render 'nav' = render 'nav'
%section.well
%h3= t '.weekly.title'
- if @group.weekly_task
= t('.weekly.desc', weekday: weekday(@group.weekday), task: @group.task_name).html_safe
- else
= t('.weekly.empty').html_safe
- if @current_user.member_of?(@group) or @current_user.role_admin?
= link_to t('.weekly.edit'), edit_foodcoop_workgroup_path(@group), class: 'btn'
%section %section
%h3= t '.title_all' %h3= t '.title_all'
= render 'list', tasks: @group.open_tasks = render 'list', tasks: @group.open_tasks

View file

@ -45,26 +45,6 @@
= f.label :role_orders = f.label :role_orders
%br/ %br/
= f.check_box :role_orders = f.check_box :role_orders
%p
= f.label :weekly_task
%br/
= f.check_box :weekly_task
%p
= f.label :weekday
%br/
= f.text_field :weekday
%p
= f.label :task_name
%br/
= f.text_field :task_name
%p
= f.label :task_description
%br/
= f.text_field :task_description
%p
= f.label :task_required_users
%br/
= f.text_field :task_required_users
%p %p
= f.label :deleted_at = f.label :deleted_at
%br/ %br/

View file

@ -12,11 +12,6 @@
%th Role Article Meta %th Role Article Meta
%th Role Finance %th Role Finance
%th Role Orders %th Role Orders
%th Weekly Task
%th Weekday
%th Task Name
%th Task Description
%th Task Required Users
%th Deleted At %th Deleted At
%th Contact Person %th Contact Person
%th Contact Phone %th Contact Phone
@ -34,11 +29,6 @@
%td= h workgroup.role_article_meta %td= h workgroup.role_article_meta
%td= h workgroup.role_finance %td= h workgroup.role_finance
%td= h workgroup.role_orders %td= h workgroup.role_orders
%td= h workgroup.weekly_task
%td= h workgroup.weekday
%td= h workgroup.task_name
%td= h workgroup.task_description
%td= h workgroup.task_required_users
%td= h workgroup.deleted_at %td= h workgroup.deleted_at
%td= h workgroup.contact_person %td= h workgroup.contact_person
%td= h workgroup.contact_phone %td= h workgroup.contact_phone

View file

@ -48,6 +48,10 @@ default: &defaults
# Comment out this option to activate this restriction # Comment out this option to activate this restriction
# stop_ordering_under: 75 # stop_ordering_under: 75
# ordergroups can only order when their balance is higher than or equal to this
# not fully enforced right now, since the check is only client-side
# minimum_balance: 0
# email address to be used as sender # email address to be used as sender
email_sender: foodsoft@foodcoop.test email_sender: foodsoft@foodcoop.test

View file

@ -10,3 +10,10 @@ class String
end end
end end
end end
class Array
def cumulative_sum
csum = 0
self.map{|val| csum += val}
end
end

View file

@ -81,6 +81,11 @@ de:
too_long: ist zu lang (nicht mehr als %{count} Zeichen) too_long: ist zu lang (nicht mehr als %{count} Zeichen)
too_short: ist zu kurz (nicht weniger als %{count} Zeichen) too_short: ist zu kurz (nicht weniger als %{count} Zeichen)
wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben) wrong_length: hat die falsche Länge (muss genau %{count} Zeichen haben)
models:
task:
attributes:
done:
exclusion: erledigte Aufgaben können nicht wöchentlich wiederholt werden
template: template:
body: ! 'Bitte überprüfen Sie die folgenden Felder:' body: ! 'Bitte überprüfen Sie die folgenden Felder:'
header: header:
@ -1423,7 +1428,7 @@ de:
sessions: sessions:
logged_in: Angemeldet! logged_in: Angemeldet!
logged_out: Abgemeldet! logged_out: Abgemeldet!
login_invalid: login_invalid: Ungültiger Benutzername oder Passwort
new: new:
forgot_password: Passwort vergessen? forgot_password: Passwort vergessen?
login: Anmelden login: Anmelden
@ -1626,12 +1631,6 @@ de:
role_finance: Finanzen role_finance: Finanzen
role_orders: Bestellverwaltung role_orders: Bestellverwaltung
role_suppliers: Lieferanten role_suppliers: Lieferanten
task_description: Beschreibung
task_duration: Vor. Dauer in Stunden
task_name: Name für Job
task_required_users: Benötige Verantwortliche
weekday: Wochentag
weekly_task: Monatlichen Job definieren?
'no': Nein 'no': Nein
required: required:
mark: ! '*' mark: ! '*'
@ -1677,6 +1676,15 @@ de:
title: Lagerartikel bearbeiten title: Lagerartikel bearbeiten
form: form:
price_hint: Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten Lagerartikeln nicht mehr verändert werden. price_hint: Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten Lagerartikeln nicht mehr verändert werden.
history:
change_quantity: Veränderung
datetime: Zeitpunkt
delivery: Lieferung
new_quantity: Neuer Bestand
order: Bestellung
reason: Ereignis
stock_changes: Verlauf anzeigen für »%{article_name}«
stock_taking: Inventur
index: index:
article: article:
article: Artikel article: Artikel
@ -1756,12 +1764,15 @@ de:
notice: Aufgabe wurde gelöscht notice: Aufgabe wurde gelöscht
edit: edit:
title: Aufgabe bearbeiten title: Aufgabe bearbeiten
warning_periodic: <strong>Warnung:</strong> Diese Aufgabe ist Teil einer Gruppe von <em>wöchentlichen Aufgaben</em>. Beim Speichern wird sie aus der Gruppe ausgeschlossen und in eine <em>gewöhnliche Aufgabe</em> umgewandelt.
error_not_found: Keine Arbeitsgruppe gefunden error_not_found: Keine Arbeitsgruppe gefunden
form: form:
search: search:
hint: Nach Nutzerin suchen hint: Nach Nutzerin suchen
noresult: Keine Nutzerin gefunden noresult: Keine Nutzerin gefunden
placeholder: Suche ... placeholder: Suche ...
submit:
periodic: Wöchentliche Aufgabe speichern
index: index:
show_group_tasks: Gruppenaufgaben anzeigen show_group_tasks: Gruppenaufgaben anzeigen
title: Aufgaben title: Aufgaben
@ -1785,10 +1796,13 @@ de:
new_task: Neue Aufgabe erstellen new_task: Neue Aufgabe erstellen
new: new:
title: Neue Aufgabe erstellen title: Neue Aufgabe erstellen
repeated: Aufgabe wird wöchentlich wiederholt
set_done: set_done:
notice: Aufgabenstatus wurde aktualisiert notice: Aufgabenstatus wurde aktualisiert
show: show:
accept_task: Aufgabe übernehmen accept_task: Aufgabe übernehmen
confirm_delete_group: Diese und alle folgenden wöchentlichen Aufgaben wirklich löschen?
delete_group: Aufgabe und folgende löschen
due_date: Fälligkeitsdatum due_date: Fälligkeitsdatum
hours: ! '%{count}h' hours: ! '%{count}h'
mark_done: Als erledigt markieren mark_done: Als erledigt markieren
@ -1796,6 +1810,7 @@ de:
title: Aufgabe anzeigen title: Aufgabe anzeigen
update: update:
notice: Aufgabe wurde aktualisiert notice: Aufgabe wurde aktualisiert
notice_converted: Aufgabe wurde aktualisiert und in eine gewöhnliche Aufgabe umgewandelt
user: user:
more: Nichts zu tun? %{tasks_link} gibt es bestimmt Arbeit more: Nichts zu tun? %{tasks_link} gibt es bestimmt Arbeit
tasks_link: Hier tasks_link: Hier
@ -1805,11 +1820,6 @@ de:
workgroup: workgroup:
title: Aufgaben für %{workgroup} title: Aufgaben für %{workgroup}
title_all: Alle Aufgaben der Gruppe title_all: Alle Aufgaben der Gruppe
weekly:
desc: ! '<p>Jeden <b>%{weekday}</b> hat diese Arbeitsgruppe folgenden Job: <b>%{task}</b></p> <p>Die Wochenaufgaben werden von der Foodsoft automatisch erstellt. Eintragen müsst Ihr Euch aber selber.</p>'
edit: Wöchentliche Aufgaben anpassen
empty: Noch keine Wochenaufgaben angelegt.
title: Wöchentliche Aufgaben
time: time:
am: vormittags am: vormittags
formats: formats:
@ -1821,6 +1831,7 @@ de:
close: Schließen close: Schließen
delete: Löschen delete: Löschen
edit: Bearbeiten edit: Bearbeiten
history: Verlauf anzeigen
marks: marks:
close: ! '&times;' close: ! '&times;'
or_cancel: oder abbrechen or_cancel: oder abbrechen

View file

@ -81,6 +81,11 @@ en:
too_long: is too long (no more than %{count} characters) too_long: is too long (no more than %{count} characters)
too_short: is too short (use more than %{count} characters) too_short: is too short (use more than %{count} characters)
wrong_length: is the wrong length (has to have exactly %{count} characters) wrong_length: is the wrong length (has to have exactly %{count} characters)
models:
task:
attributes:
done:
exclusion: finished tasks may not be repeated weekly
template: template:
body: ! 'Please check the following fields:' body: ! 'Please check the following fields:'
header: header:
@ -1628,12 +1633,6 @@ en:
role_finance: Finances role_finance: Finances
role_orders: Order management role_orders: Order management
role_suppliers: Suppliers role_suppliers: Suppliers
task_description: Description
task_duration: Duration in hours
task_name: Task name
task_required_users: People required
weekday: Weekday
weekly_task: Define monthly task?
'no': 'No' 'no': 'No'
required: required:
mark: ! '*' mark: ! '*'
@ -1679,6 +1678,15 @@ en:
title: Edit stock articles title: Edit stock articles
form: form:
price_hint: To avoid choas, it is not possible to edit the prices of already added stock articles until further notice. price_hint: To avoid choas, it is not possible to edit the prices of already added stock articles until further notice.
history:
change_quantity: Change
datetime: Time
delivery: Delivery
new_quantity: New quantity
order: Order
reason: Reason
stock_changes: Stock quantity changes of %{article_name}
stock_taking: Inventory
index: index:
article: article:
article: Article article: Article
@ -1758,12 +1766,15 @@ en:
notice: Task has been deleted notice: Task has been deleted
edit: edit:
title: Edit task title: Edit task
warning_periodic: <strong>Warning:</strong> This task is part of a group of <em>weekly tasks</em>. When saving it will be excluded from the group and it will be converted to a <em>regular task</em>.
error_not_found: No workgroup found error_not_found: No workgroup found
form: form:
search: search:
hint: Search for user hint: Search for user
noresult: No user found noresult: No user found
placeholder: Search ... placeholder: Search ...
submit:
periodic: Save weekly task
index: index:
show_group_tasks: Show group tasks show_group_tasks: Show group tasks
title: Tasks title: Tasks
@ -1787,10 +1798,13 @@ en:
new_task: Create new task new_task: Create new task
new: new:
title: Create new tasks title: Create new tasks
repeated: Task is repeated weekly
set_done: set_done:
notice: The state of the task has been updated notice: The state of the task has been updated
show: show:
accept_task: Accept task accept_task: Accept task
confirm_delete_group: Really delete this and all subsequent tasks?
delete_group: Delete task and subsequent
due_date: Due date due_date: Due date
hours: ! '%{count}h' hours: ! '%{count}h'
mark_done: Mark task as done mark_done: Mark task as done
@ -1798,6 +1812,7 @@ en:
title: Show task title: Show task
update: update:
notice: Task has been updated notice: Task has been updated
notice_converted: Task has been updated and was converted to a regular task
user: user:
more: Nothing to do? %{tasks_link} are tasks for sure. more: Nothing to do? %{tasks_link} are tasks for sure.
tasks_link: Here tasks_link: Here
@ -1807,11 +1822,6 @@ en:
workgroup: workgroup:
title: Tasks for %{workgroup} title: Tasks for %{workgroup}
title_all: All group tasks title_all: All group tasks
weekly:
desc: ! '<p>Every <b>%{weekday}</b> this workgroup has the following job: <b>%{task}</b></p> <p>The weektask has been created by Foodsoft automatically. You still have to sign up for it yourself.</p>'
edit: Edit weekly tasks
empty: No weekly tasks created yet.
title: Weekly tasks
time: time:
am: morning am: morning
formats: formats:
@ -1823,6 +1833,7 @@ en:
close: Close close: Close
delete: Delete delete: Delete
edit: Edit edit: Edit
history: Show history
marks: marks:
close: ! '&times;' close: ! '&times;'
or_cancel: or cancel or_cancel: or cancel

View file

@ -81,6 +81,11 @@ nl:
too_long: is te lang (niet meer dan %{count} tekens) too_long: is te lang (niet meer dan %{count} tekens)
too_short: is te kort (niet minder dan %{count} tekens) too_short: is te kort (niet minder dan %{count} tekens)
wrong_length: heeft de verkeerde lengte (moet precies %{count} tekens zijn) wrong_length: heeft de verkeerde lengte (moet precies %{count} tekens zijn)
models:
task:
attributes:
done:
exclusion:
template: template:
body: ! 'Controleer de volgende velden:' body: ! 'Controleer de volgende velden:'
header: header:
@ -265,10 +270,10 @@ nl:
edit_all_table: edit_all_table:
available_desc: beschikbaar available_desc: beschikbaar
available_short: besch. available_short: besch.
order_number_desc: bestelnummer order_number_desc: Bestelnummer
order_number_short: best.nr. order_number_short: Best.nr.
price_desc: netto prijs price_desc: Netto prijs
price_short: prijs price_short: Prijs
unit_quantity_desc: Groothandelsverpakkingsgrootte unit_quantity_desc: Groothandelsverpakkingsgrootte
unit_quantity_short: Gr.Eenh. unit_quantity_short: Gr.Eenh.
form: form:
@ -542,7 +547,7 @@ nl:
total_fc: Som (FC-prijs) total_fc: Som (FC-prijs)
units: Eenheden units: Eenheden
index: index:
title: Gesloten orders title: Gesloten bestellingen
invoice: invoice:
edit: Factuur bewerken edit: Factuur bewerken
invoice_amount: ! 'Factuurbedrag:' invoice_amount: ! 'Factuurbedrag:'
@ -573,8 +578,8 @@ nl:
orders: orders:
clear: afrekenen clear: afrekenen
cleared: afgerekend (%{amount}) cleared: afgerekend (%{amount})
close: direct afsluiten close: direct afrekenen
confirm: Weet je zeker dat de je bestelling wilt afsluiten? confirm: Weet je zeker dat de je bestelling wilt afrekenen?
end: Einde end: Einde
ended: gesloten ended: gesloten
last_edited_by: Laatst aangepast door last_edited_by: Laatst aangepast door
@ -1092,7 +1097,7 @@ nl:
number: number:
currency: currency:
format: format:
delimiter: ! ',' delimiter: ! ' '
format: ! '%n %u' format: ! '%n %u'
precision: 2 precision: 2
separator: ! ',' separator: ! ','
@ -1425,7 +1430,7 @@ nl:
description: Omschrijving description: Omschrijving
email: Email email: Email
note: Notitie note: Notitie
order_number: Order nummer order_number: Bestelnummer
ordergroup: Huishouden ordergroup: Huishouden
password: Wachtwoord password: Wachtwoord
password_confirmation: Wachtwoord herhalen password_confirmation: Wachtwoord herhalen
@ -1450,7 +1455,7 @@ nl:
note: Notitie note: Notitie
number: Nummer number: Nummer
order: Bestelling order: Bestelling
paid_on: Betaalt op paid_on: Betaald op
supplier: Leverancier supplier: Leverancier
message: message:
body: body:
@ -1513,16 +1518,10 @@ nl:
workgroup: workgroup:
next_weekly_tasks_number: next_weekly_tasks_number:
role_admin: role_admin:
role_article_meta: role_article_meta: Artikelbestand
role_finance: role_finance: Financiën
role_orders: role_orders:
role_suppliers: role_suppliers: Leveranciers
task_description:
task_duration:
task_name:
task_required_users:
weekday:
weekly_task:
'no': Nee 'no': Nee
required: required:
mark: ! '*' mark: ! '*'
@ -1568,6 +1567,15 @@ nl:
title: title:
form: form:
price_hint: price_hint:
history:
change_quantity:
datetime:
delivery:
new_quantity:
order:
reason:
stock_changes:
stock_taking:
index: index:
article: article:
article: article:
@ -1647,12 +1655,15 @@ nl:
notice: notice:
edit: edit:
title: title:
warning_periodic:
error_not_found: error_not_found:
form: form:
search: search:
hint: hint:
noresult: noresult:
placeholder: placeholder:
submit:
periodic:
index: index:
show_group_tasks: show_group_tasks:
title: title:
@ -1676,10 +1687,13 @@ nl:
new_task: new_task:
new: new:
title: title:
repeated:
set_done: set_done:
notice: notice:
show: show:
accept_task: accept_task:
confirm_delete_group:
delete_group:
due_date: due_date:
hours: hours:
mark_done: mark_done:
@ -1687,6 +1701,7 @@ nl:
title: title:
update: update:
notice: notice:
notice_converted:
user: user:
more: more:
tasks_link: tasks_link:
@ -1696,11 +1711,6 @@ nl:
workgroup: workgroup:
title: title:
title_all: title_all:
weekly:
desc:
edit:
empty:
title:
time: time:
am: morgen am: morgen
formats: formats:
@ -1712,6 +1722,7 @@ nl:
close: Sluiten close: Sluiten
delete: Verwijder delete: Verwijder
edit: Bewerk edit: Bewerk
history:
marks: marks:
close: ! '&times;' close: ! '&times;'
or_cancel: of annuleren or_cancel: of annuleren

View file

@ -96,6 +96,8 @@ Foodsoft::Application.routes.draw do
get :articles_search get :articles_search
get :fill_new_stock_article_form get :fill_new_stock_article_form
end end
get :history
end end
resources :suppliers do resources :suppliers do

View file

@ -0,0 +1,13 @@
class CreatePeriodicTaskGroups < ActiveRecord::Migration
def change
create_table :periodic_task_groups do |t|
t.date :next_task_date
t.timestamps
end
change_table :tasks do |t|
t.references :periodic_task_group
end
end
end

View file

@ -0,0 +1,60 @@
class MoveWeeklyTasks < ActiveRecord::Migration
def up
Workgroup.where(weekly_task: true).each do |workgroup|
task_group = PeriodicTaskGroup.create
puts "Moving weekly task for workgroup #{workgroup.name} to group #{task_group.id}"
workgroup.tasks.undone.each do |task|
task.update_column(:periodic_task_group_id, task_group.id) if weekly_task?(workgroup, task)
end
tasks = task_group.tasks.order(:due_date)
task_group.next_task_date = tasks.last.due_date + PeriodicTaskGroup::PeriodDays unless tasks.empty?
task_group.save!
puts "Associated #{tasks.count} tasks with group and set next_task_date to #{task_group.next_task_date}"
end
end
def down
PeriodicTaskGroup.all.each do |task_group|
unless task_group.tasks.empty?
task = task_group.tasks.first
workgroup = task.workgroup
puts "Writing task data of group #{task_group.id} to workgroup #{workgroup.name}"
workgroup_attributes = {
weekly_task: true,
weekday: task.due_date.days_to_week_start(:sunday),
task_name: task.name,
task_description: task.description,
task_required_users: task.required_users,
task_duration: task.duration
}
workgroup.update_attributes workgroup_attributes
task_group.tasks.update_all weekly: true
end
end
end
private
def weekly_task?(workgroup, task)
group_task = {
weekday: workgroup.weekday,
name: workgroup.task_name,
description: workgroup.task_description,
required_users: workgroup.task_required_users,
duration: workgroup.task_duration,
weekly: true,
done: false,
workgroup_id: workgroup.id
}
task_task = {
weekday: task.due_date.days_to_week_start(:sunday),
name: task.name,
description: task.description,
required_users: task.required_users,
duration: task.duration,
weekly: task.weekly,
done: task.done,
workgroup_id: task.workgroup_id
}
group_task == task_task
end
end

View file

@ -0,0 +1,9 @@
class RemoveWeeklyFromTasks < ActiveRecord::Migration
def up
remove_column :tasks, :weekly
end
def down
add_column :tasks, :weekly, :boolean
end
end

View file

@ -0,0 +1,19 @@
class RemoveWeeklyTaskFromGroups < ActiveRecord::Migration
def up
remove_column :groups, :weekly_task
remove_column :groups, :weekday
remove_column :groups, :task_name
remove_column :groups, :task_description
remove_column :groups, :task_required_users
remove_column :groups, :task_duration
end
def down
add_column :groups, :task_duration, :integer
add_column :groups, :task_required_users, :integer
add_column :groups, :task_description, :string
add_column :groups, :task_name, :string
add_column :groups, :weekday, :integer
add_column :groups, :weekly_task, :boolean
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20121230142516) do ActiveRecord::Schema.define(:version => 20130624085246) do
create_table "article_categories", :force => true do |t| create_table "article_categories", :force => true do |t|
t.string "name", :default => "", :null => false t.string "name", :default => "", :null => false
@ -143,17 +143,11 @@ ActiveRecord::Schema.define(:version => 20121230142516) do
t.boolean "role_article_meta", :default => false, :null => false t.boolean "role_article_meta", :default => false, :null => false
t.boolean "role_finance", :default => false, :null => false t.boolean "role_finance", :default => false, :null => false
t.boolean "role_orders", :default => false, :null => false t.boolean "role_orders", :default => false, :null => false
t.boolean "weekly_task", :default => false
t.integer "weekday"
t.string "task_name"
t.string "task_description"
t.integer "task_required_users", :default => 1
t.datetime "deleted_at" t.datetime "deleted_at"
t.string "contact_person" t.string "contact_person"
t.string "contact_phone" t.string "contact_phone"
t.string "contact_address" t.string "contact_address"
t.text "stats" t.text "stats"
t.integer "task_duration", :default => 1
t.integer "next_weekly_tasks_number", :default => 8 t.integer "next_weekly_tasks_number", :default => 8
t.boolean "ignore_apple_restriction", :default => false t.boolean "ignore_apple_restriction", :default => false
end end
@ -268,6 +262,12 @@ ActiveRecord::Schema.define(:version => 20121230142516) do
add_index "pages", ["permalink"], :name => "index_pages_on_permalink" add_index "pages", ["permalink"], :name => "index_pages_on_permalink"
add_index "pages", ["title"], :name => "index_pages_on_title" add_index "pages", ["title"], :name => "index_pages_on_title"
create_table "periodic_task_groups", :force => true do |t|
t.date "next_task_date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "stock_changes", :force => true do |t| create_table "stock_changes", :force => true do |t|
t.integer "delivery_id" t.integer "delivery_id"
t.integer "order_id" t.integer "order_id"
@ -316,8 +316,8 @@ ActiveRecord::Schema.define(:version => 20121230142516) do
t.datetime "created_on", :null => false t.datetime "created_on", :null => false
t.datetime "updated_on", :null => false t.datetime "updated_on", :null => false
t.integer "required_users", :default => 1 t.integer "required_users", :default => 1
t.boolean "weekly"
t.integer "duration", :default => 1 t.integer "duration", :default => 1
t.integer "periodic_task_group_id"
end end
add_index "tasks", ["due_date"], :name => "index_tasks_on_due_date" add_index "tasks", ["due_date"], :name => "index_tasks_on_due_date"

View file

@ -16,21 +16,6 @@ namespace :foodsoft do
end end
end end
desc "Create upcoming workgroups tasks (next 3 to 7 weeks)"
task :create_upcoming_weekly_tasks => :environment do
workgroups = Workgroup.where(weekly_task: true)
for workgroup in workgroups
puts "Create weekly tasks for #{workgroup.name}"
# Loop through next tasks weekly tasks method,
# skip the next 3 weeks, to allow manually deleting tasks
workgroup.next_weekly_tasks[3..-1].each do |date|
unless workgroup.tasks.exists?({:due_date => date, :weekly => true})
workgroup.tasks.create(workgroup.task_attributes(date))
end
end
end
end
desc "Notify workgroup of upcoming weekly task" desc "Notify workgroup of upcoming weekly task"
task :notify_users_of_weekly_task => :environment do task :notify_users_of_weekly_task => :environment do
for workgroup in Workgroup.all for workgroup in Workgroup.all
@ -50,4 +35,15 @@ namespace :foodsoft do
end end
end end
end end
desc "Create upcoming periodic tasks"
task :create_upcoming_periodic_tasks => :environment do
for tg in PeriodicTaskGroup.all
if tg.has_next_task?
while tg.next_task_date.nil? or tg.next_task_date < Date.today + 50
tg.create_next_task
end
end
end
end
end end