Second part of stock-integration.

Introduced StockArticle and a special page for ordering from stock. StockChanges will be created and the StockArticle.quantity
updated in 'order.close!'.
This commit is contained in:
Benjamin Meichsner 2009-02-06 16:26:35 +01:00
parent 1912a3fd80
commit c17b63b192
37 changed files with 616 additions and 340 deletions

View File

@ -22,17 +22,14 @@ class DeliveriesController < ApplicationController
def new
@delivery = @supplier.deliveries.build
3.times { @delivery.stock_changes.build }
@supplier.stock_articles.each { |article| @delivery.stock_changes.build(:stock_article => article) }
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @delivery }
end
end
def edit
@delivery = Delivery.find(params[:id])
end
def create
@delivery = Delivery.new(params[:delivery])
@ -48,8 +45,10 @@ class DeliveriesController < ApplicationController
end
end
# PUT /deliveries/1
# PUT /deliveries/1.xml
def edit
@delivery = Delivery.find(params[:id])
end
def update
@delivery = Delivery.find(params[:id])
@ -75,12 +74,29 @@ class DeliveriesController < ApplicationController
end
end
def add_stock_article
article = @supplier.stock_articles.build(params[:stock_article])
render :update do |page|
if article.save
logger.debug "new StockArticle: #{article.id}"
page.insert_html :top, 'stock_changes', :partial => 'stock_change',
:locals => {:stock_change => article.stock_changes.build}
page.replace_html 'new_stock_article', :partial => 'new_stock_article',
:locals => {:stock_article => @supplier.stock_articles.build}
else
page.replace_html 'new_stock_article', :partial => 'new_stock_article',
:locals => {:stock_article => article}
end
end
end
def drop_stock_change
stock_change = StockChange.find(params[:stock_change_id])
stock_change.destroy
render :update do |page|
page.visual_effect(:DropOut, "stock_change_#{stock_change.id}")
page.visual_effect :DropOut, "stock_change_#{stock_change.id}"
end
end
end

View File

@ -136,7 +136,8 @@ class Finance::BalancingController < ApplicationController
render :update do |page|
if goa.save
goa.group_order.update_price! # Updates the price attribute of new GroupOrder
goa.group_order.update_price! # Update the price attribute of new GroupOrder
order_article.update_results! if order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
page["edit_box"].hide
page["group_order_articles_#{order_article.id}"].replace_html :partial => 'group_order_articles',
@ -163,7 +164,8 @@ class Finance::BalancingController < ApplicationController
render :update do |page|
if goa.update_attributes(params[:group_order_article])
goa.group_order.update_price! # Updates the price attribute of new GroupOrder
goa.group_order.update_price! # Update the price attribute of new GroupOrder
goa.order_article.update_results! if goa.order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
page["edit_box"].hide
page["group_order_articles_#{goa.order_article.id}"].replace_html :partial => 'group_order_articles',
@ -180,7 +182,8 @@ class Finance::BalancingController < ApplicationController
goa = GroupOrderArticle.find(params[:id])
goa.destroy
goa.group_order.update_price! # Updates the price attribute of new GroupOrder
goa.order_article.update_results! if goa.order_article.article.is_a?(StockArticle) # Update units_to_order of order_article
render :update do |page|
page["edit_box"].hide
page["group_order_articles_#{goa.order_article.id}"].replace_html :partial => 'group_order_articles',

View File

@ -3,18 +3,18 @@
class OrderingController < ApplicationController
# Security
before_filter :ensure_ordergroup_member
before_filter :ensure_open_order, :only => [:order, :saveOrder]
before_filter :ensure_open_order, :only => [:order, :stock_order, :saveOrder]
verify :method => :post, :only => [:saveOrder], :redirect_to => {:action => :index}
# Index page.
def index
def index
end
# Edit a current order.
def order
@open_orders = Order.open
@other_orders = @open_orders.reject{|order| order == @order}
def order
redirect_to :action => 'stock_order', :id => @order if @order.stockit?
# Load order article data...
@articles_grouped_by_category = @order.articles_grouped_by_category
# save results of earlier orders in array
@ -59,6 +59,47 @@ class OrderingController < ApplicationController
end
end
end
def stock_order
# Load order article data...
@articles_grouped_by_category = @order.articles_grouped_by_category
# save results of earlier orders in array
ordered_articles = Array.new
@group_order = @order.group_orders.find(:first,
:conditions => "ordergroup_id = #{@ordergroup.id}", :include => :group_order_articles)
if @group_order
# Group has already ordered, so get the results...
for goa in @group_order.group_order_articles
ordered_articles[goa.order_article_id] = {:quantity => goa.quantity,
:tolerance => goa.tolerance,
:quantity_result => goa.result(:quantity),
:tolerance_result => goa.result(:tolerance)}
end
@version = @group_order.lock_version
@availableFunds = @ordergroup.get_available_funds(@group_order)
else
@version = 0
@availableFunds = @ordergroup.get_available_funds
end
# load prices ....
@price = Array.new; @quantity_available = Array.new
@others_quantity = Array.new; @quantity = Array.new; @quantity_result = Array.new; @used_quantity = Array.new; @unused_quantity = Array.new
i = 0;
@articles_grouped_by_category.each do |category_name, order_articles|
for order_article in order_articles
# price/unit size
@price[i] = order_article.article.fc_price
@quantity_available[i] = order_article.article.quantity_available(@order)
# quantity
@quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity] : 0)
@others_quantity[i] = order_article.quantity - @quantity[i]
@used_quantity[i] = (ordered_articles[order_article.id] ? ordered_articles[order_article.id][:quantity_result] : 0)
i += 1
end
end
end
# Update changes to a current order.
def saveOrder

View File

@ -1,6 +1,6 @@
class StockitController < ApplicationController
def index
@articles = Article.in_stock
@articles = StockArticle.all
end
end

View File

@ -22,6 +22,7 @@
# updated_at :datetime
# quantity :decimal(, ) default(0.0)
# deleted_at :datetime
# type :string(255)
#
class Article < ActiveRecord::Base
@ -32,9 +33,7 @@ class Article < ActiveRecord::Base
belongs_to :supplier
belongs_to :article_category
has_many :article_prices, :order => "created_at"
has_many :stock_changes
named_scope :in_stock, :conditions => "quantity > 0", :order => 'suppliers.name', :include => :supplier
named_scope :available, :conditions => {:availability => true}
# Validations
@ -173,11 +172,6 @@ class Article < ActiveRecord::Base
end
end
# Update the quantity of items in stock
def update_quantity!
update_attribute :quantity, stock_changes.collect(&:quantity).sum
end
protected
# Checks if the article is in use before it will deleted

View File

@ -13,7 +13,7 @@ class Delivery < ActiveRecord::Base
belongs_to :supplier
has_one :invoice
has_many :stock_changes
has_many :stock_changes, :dependent => :destroy
named_scope :recent, :order => 'created_at DESC', :limit => 10

View File

@ -9,8 +9,7 @@
# quantity :integer default(0), not null
# tolerance :integer default(0), not null
# updated_on :datetime not null
# quantity_result :integer
# tolerance_result :integer
# result :integer
#
# A GroupOrderArticle stores the sum of how many items of an OrderArticle are ordered as part of a GroupOrder.
@ -106,9 +105,10 @@ class GroupOrderArticle < ActiveRecord::Base
# See description of the ordering algorithm in the general application documentation for details.
def calculate_result
quantity = tolerance = 0
stockit = order_article.article.is_a?(StockArticle)
# Get total
total = order_article.units_to_order * order_article.price.unit_quantity
total = stockit ? order_article.article.quantity : order_article.units_to_order * order_article.price.unit_quantity
logger.debug("<#{order_article.article.name}>.unitsToOrder => items ordered: #{order_article.units_to_order} => #{total}")
if (total > 0)
@ -130,7 +130,7 @@ class GroupOrderArticle < ActiveRecord::Base
end
i += 1
end
# Determine tolerance to be ordered...
if (total_quantity < total)
logger.debug("determining additional items to be ordered from tolerance")
@ -143,7 +143,7 @@ class GroupOrderArticle < ActiveRecord::Base
tolerance += q
end
i += 1
end
end
end
logger.debug("determined quantity/tolerance/total: #{quantity} / #{tolerance} / #{quantity + tolerance}")

View File

@ -24,6 +24,7 @@ class Order < ActiveRecord::Base
has_many :ordergroups, :through => :group_orders
has_one :invoice
has_many :comments, :class_name => "OrderComment", :order => "created_at"
has_many :stock_changes
belongs_to :supplier
belongs_to :updated_by, :class_name => "User", :foreign_key => "updated_by_user_id"
@ -51,8 +52,10 @@ class Order < ActiveRecord::Base
def articles_for_ordering
if stockit?
Article.in_stock.all(:include => :article_category,
:order => 'article_categories.name, articles.name').group_by { |a| a.article_category.name }
StockArticle.available.all(:include => :article_category,
:order => 'article_categories.name, articles.name').reject{ |a|
a.quantity_available == 0
}.group_by { |a| a.article_category.name }
else
supplier.articles.available.all.group_by { |a| a.article_category.name }
end
@ -95,7 +98,7 @@ class Order < ActiveRecord::Base
def group_order(ordergroup)
group_orders.first :conditions => { :ordergroup_id => ordergroup.id }
end
# Returns OrderArticles in a nested Array, grouped by category and ordered by article name.
# The array has the following form:
# e.g: [["drugs",[teethpaste, toiletpaper]], ["fruits" => [apple, banana, lemon]]]
@ -196,6 +199,14 @@ class Order < ActiveRecord::Base
price = group_order.price * -1 # decrease! account balance
group_order.ordergroup.add_financial_transaction(price, transaction_note, user)
end
if stockit? # Decreases the quantity of stock_articles
for oa in order_articles.all(:include => :article)
oa.update_results! # Update units_to_order of order_article
stock_changes.create! :stock_article => oa.article, :quantity => oa.units_to_order*-1
end
end
self.update_attributes! :state => 'closed', :updated_by => user
end
end

View File

@ -48,12 +48,15 @@ class OrderArticle < ActiveRecord::Base
end
# Update quantity/tolerance/units_to_order from group_order_articles
# This is only used in opened orders.
def update_results!
quantity = group_order_articles.collect(&:quantity).sum
tolerance = group_order_articles.collect(&:tolerance).sum
update_attributes(:quantity => quantity, :tolerance => tolerance,
:units_to_order => calculate_units_to_order(quantity, tolerance))
if order.open?
quantity = group_order_articles.collect(&:quantity).sum
tolerance = group_order_articles.collect(&:tolerance).sum
update_attributes(:quantity => quantity, :tolerance => tolerance,
:units_to_order => calculate_units_to_order(quantity, tolerance))
elsif order.finished?
update_attribute(:units_to_order, group_order_articles.collect(&:result).sum)
end
end
# Returns how many units of the belonging article need to be ordered given the specified order quantity and tolerance.

View File

@ -0,0 +1,49 @@
# == Schema Information
# Schema version: 20090120184410
#
# Table name: articles
#
# id :integer not null, primary key
# name :string(255) default(""), not null
# supplier_id :integer default(0), not null
# article_category_id :integer default(0), not null
# unit :string(255) default(""), not null
# note :string(255)
# availability :boolean default(TRUE), not null
# manufacturer :string(255)
# origin :string(255)
# shared_updated_on :datetime
# price :decimal(, )
# tax :float
# deposit :decimal(, ) default(0.0)
# unit_quantity :integer default(1), not null
# order_number :string(255)
# created_at :datetime
# updated_at :datetime
# quantity :decimal(, ) default(0.0)
# deleted_at :datetime
# type :string(255)
#
class StockArticle < Article
has_many :stock_changes
named_scope :available, :conditions => "quantity > 0"
# Update the quantity of items in stock
def update_quantity!
update_attribute :quantity, stock_changes.collect(&:quantity).sum
end
# Check for unclosed orders and substract its ordered quantity
def quantity_available(exclude_order = nil)
available = quantity
for order in Order.stockit.all(:conditions => "state = 'open' OR state = 'finished'")
unless order == exclude_order
order_article = order.order_articles.first(:conditions => {:article_id => id})
available -= order_article.units_to_order if order_article
end
end
available
end
end

View File

@ -1,22 +1,22 @@
# == Schema Information
# Schema version: 20090119155930
# Schema version: 20090120184410
#
# Table name: stock_changes
#
# id :integer not null, primary key
# delivery_id :integer
# order_id :integer
# article_id :integer
# quantity :decimal(6, 2) default(0.0)
# created_at :datetime
# id :integer not null, primary key
# delivery_id :integer
# order_id :integer
# stock_article_id :integer
# quantity :decimal(, ) default(0.0)
# created_at :datetime
#
class StockChange < ActiveRecord::Base
belongs_to :delivery
belongs_to :order
belongs_to :article
belongs_to :stock_article
validates_presence_of :article_id, :quantity
validates_presence_of :stock_article_id, :quantity
validates_numericality_of :quantity
after_save :update_article_quantity
@ -25,6 +25,6 @@ class StockChange < ActiveRecord::Base
protected
def update_article_quantity
article.update_quantity!
stock_article.update_quantity!
end
end

View File

@ -26,6 +26,7 @@ class Supplier < ActiveRecord::Base
has_many :articles, :dependent => :destroy,
:include => [:article_category], :order => 'article_categories.name, articles.name'
has_many :stock_articles
has_many :orders
has_many :deliveries
has_many :invoices

View File

@ -0,0 +1,34 @@
- remote_form_for stock_article, :url => add_stock_article_supplier_deliveries_path(@supplier) do |form|
= form.error_messages
%p
remote_link_to "Artikel aus dem Katalog wählen"...
%p
= form.label :name
%br/
= form.text_field :name
%p
= form.label :unit
%br/
= form.text_field :unit
%p
= form.label :note
%br/
= form.text_field :note
%p
= form.label :price
%br/
= form.text_field :price
%p
= form.label :tax
%br/
= form.text_field :tax, :value => (stock_article.tax || 7.0)
%p
= form.label :deposit
%br/
= form.text_field :deposit
%p
Kategorie:
= form.select :article_category, ArticleCategory.all(:order => 'name').collect { |c| [c.name, c.id] }
%p
= submit_tag "Artikel speichern"

View File

@ -1,6 +1,9 @@
%p
- fields_for "delivery[stock_change_attributes][]", stock_change do |form|
= form.select :article_id, articles_for_select(@supplier), :prompt => " -- Artikel auswählen -- "
= form.hidden_field :stock_article_id
Menge
= form.text_field :quantity, :size => 5, :autocomplete => 'off'
= link_to_function "Löschen", "$(this).up('p').remove()"
- article = stock_change.stock_article
%b= article.name
= "(#{number_to_currency(article.price)} / #{article.unit})"
//= link_to_function "Löschen", "$(this).up('p').remove()"

View File

@ -1,4 +1,27 @@
- title "Neue Lieferung von #{@supplier.name}"
- render :layout => 'form' do
= render :partial => 'stock_change', :collection => @delivery.stock_changes
.left_column
- form_for([@supplier,@delivery]) do |f|
.box_title
%h2 Lieferung anlegen
.column_content
= f.error_messages
= f.hidden_field :supplier_id
%p
%b= f.label :delivered_on
= f.date_select :delivered_on
%h2 Lagerartikel des Lieferanten
#stock_changes
= render :partial => 'stock_change', :collection => @delivery.stock_changes
%p
= f.submit "Lieferung anlegen"
.right_column{:style => "width:35em;"}
.box_title
%h2 Neuen Lagerartikel anlegen
.column_content
#new_stock_article
= render :partial => 'new_stock_article', :locals => {:stock_article => @supplier.stock_articles.build}
%p{:style => "clear:both"}
= link_to 'Zurück', supplier_deliveries_path(@supplier)

View File

@ -16,10 +16,10 @@
%th Artikel
%th Einheit
%th Menge
- for stock_change in @delivery.stock_changes.find :all, :include => :article
- for stock_change in @delivery.stock_changes.find :all, :include => :stock_article
%tr
%td= stock_change.article.name
%td= stock_change.article.unit
%td= stock_change.stock_article.name
%td= stock_change.stock_article.unit
%td= stock_change.quantity
%br/

View File

@ -17,7 +17,7 @@
%td{:id => "group_order_article_#{group_order_article.id}_quantity"}
= group_order_article.result
%td.currency
= number_to_currency(group_order_article.order_article.price.fc_price * group_order_article.quantity, :unit => "")
= number_to_currency(group_order_article.order_article.price.fc_price * group_order_article.result, :unit => "")
%td.actions{:style=>"width:1em"}
= remote_link_to icon(:edit), :update => 'edit_box', |
:url => {:action => 'edit_group_order_article', :id => group_order_article}, |

View File

@ -8,11 +8,13 @@
%h2 Zusammenfassung
.column_content#summary
= render :partial => "summary", :locals => {:order => @order}
.left_column{:style => 'width: 24em'}
.box_title
%h2 Rechnung
.column_content#invoice
= render :partial => "invoice", :locals => {:invoice => @order.invoice}
- unless @order.stockit?
.left_column{:style => 'width: 24em'}
.box_title
%h2 Rechnung
.column_content#invoice
= render :partial => "invoice", :locals => {:invoice => @order.invoice}
.right_column{:style => 'width: 20em'}
.box_title

View File

@ -0,0 +1,48 @@
- title "Bestellen"
.left_column{:style => "width:49em"}
.box_title
%h2=h @order.name
.column_content
%table
%tr{:valign => "top"}
%td{:width => "60%"}
%p
%b Lieferant:
=h @order.name
%p
%b Ende:
=h format_time(@order.ends)
- if @group_order && @group_order.updated_by
%p
%b Zuletzt bestellt:
=h @group_order.updated_by.nick if @group_order.updated_by
= "(#{format_time(@group_order.updated_on)})"
%p
%b Verfügbares Guthaben:
= number_to_currency(@availableFunds)
%td
- unless @order.note.empty?
%p
%b Notiz:
= simple_format(@order.note)
- unless @order.stockit? || @order.supplier.min_order_quantity.blank?
%p
%b Mindestellmenge:
=h @order.supplier.min_order_quantity
%p
%b Gesamtbestellmenge bisher:
= number_to_currency @order.sum
- orders = Order.open.reject{ |order| order == @order }
- unless orders.empty?
.right_column{:style => "width:22em"}
.box_title
%h2 Anderer Bestellungen
.column_content
%table
- for order in @other_orders
%tr
%td
= link_to_function order.name, "if (confirmSwitchOrder()) (window.location = '#{ url_for(:action => 'order', :id => order) }' )"
%td= "noch #{time_ago_in_words(order.ends)}" if order.ends

View File

@ -1,164 +1,104 @@
<h1>Bestellen</h1>
<%= render :partial => 'order_head' %>
<div class="left_column" style="width:49em">
<div class="box_title"><h2><%=h @order.name %></h2></div>
<div class="column_content">
<table>
<tr valign="top">
<td width="60%">
<p><b>Lieferant:</b> <%=h @order.name %></p>
<p><b>Ende:</b> <%=h format_time(@order.ends) %></p>
<% if @group_order && @group_order.updated_by -%>
<p><b>Zuletzt bestellt:</b> <%=h @group_order.updated_by.nick if @group_order.updated_by %> (<%= format_time(@group_order.updated_on) %>)</p>
<% end -%>
<p><b>Verfügbares Guthaben:</b> <%= number_to_currency(@availableFunds) %></p>
</td>
<td>
<% unless @order.note.empty? %>
<p>
<b>Notiz:</b>
</p>
<%= simple_format(@order.note) %>
<% end %>
<% unless @order.stockit? || @order.supplier.min_order_quantity.blank? -%>
<p>
<b>Mindestellmenge:</b>
<%=h @order.supplier.min_order_quantity %>
</p>
<% end -%>
<p>
<b>Gesamtbestellmenge bisher:</b>
<%= number_to_currency @order.sum %>
</p>
</td>
</tr>
</table>
</div>
</div>
<%- if !@other_orders.empty? -%>
<div class="right_column" style="width:22em">
<div class="box_title">
<h2>Andere Bestellungen</h2>
</div>
<div class="column_content">
<table>
<% for order in @other_orders -%>
<tr>
<td>
<%= link_to_function order.name, "if (confirmSwitchOrder()) (window.location = '#{ url_for(:action => 'order', :id => order) }' )" %>
</td>
<td>noch <%= time_ago_in_words(order.ends) if order.ends -%></td>
</tr>
<% end -%>
</table>
</div>
</div>
<%- end -%>
<br style="clear:both" />
<div class="single_column">
<% form_tag(:action => 'saveOrder', :id => @order) do %>
<div class="box_title">
<h2>Artikel</h2>
</div>
<div class="column_content">
<table id="order" class="list">
<thead>
<tr>
<th>Name</th>
<th></th>
<th>Herstellerin</th>
<th style="width:7em;"><%= @order.stockit? ? "im Lager" : "Gebinde" -%></th>
<th style="width:4.5em;">Preis</th>
<th id="col_packages"><acronym title="insgesamt bestellte Gebinde">Best</acronym></th>
<th id="col_required">Menge</th>
<% unless @order.stockit? -%>
<th id="col_tolerance">Toleranz</th>
<% end -%>
<th>Summe</th>
</tr>
</thead>
<tbody>
<div class="single_column" style="clear:both;">
<% form_tag(:action => 'saveOrder', :id => @order) do %>
<div class="box_title">
<h2>Artikel</h2>
</div>
<div class="column_content">
<table id="order" class="list">
<thead>
<tr>
<th>Name</th>
<th></th>
<th>Herstellerin</th>
<th style="width:7em;">Gebinde</th>
<th style="width:4.5em;">Preis</th>
<th id="col_packages"><acronym title="insgesamt bestellte Gebinde">Best</acronym></th>
<th id="col_required">Menge</th>
<th id="col_tolerance">Toleranz</th>
<th>Summe</th>
</tr>
</thead>
<tbody>
<%-
total = 0
i = 0
@articles_grouped_by_category.each do |category, order_articles|
-%>
<tr style="background-color:#EFEFEF">
<td style="text-align:left"><b><%=h category %></b></td>
<td colspan="9"></td>
</tr>
<tr style="background-color:#EFEFEF">
<td style="text-align:left"><b><%=h category %></b></td>
<td colspan="9"></td>
</tr>
<%-
order_articles.each do |order_article|
article_total = @price[i] * (@tolerance[i] + @quantity[i]);
total += article_total
-%>
<tr class="<%= cycle('even', 'odd', :name => 'articles') %>" valign="top">
<td class="name">
<% unless order_article.article.note.blank? %>
<%= order_article.article.name %> <%= image_tag "lamp_grey.png", {:alt => _("Show note"), :size => "15x16", :border => "0", :onmouseover => "$('note_#{i}').show();", :onmouseout => "$('note_#{i}').hide();" }%>
<% else %>
<%= order_article.article.name %>
<% end %>
</td>
<td><%=h order_article.article.origin %></td>
<td><%=h truncate order_article.article.manufacturer, :length => 11 %></td>
<td><%= @order.stockit? ? order_article.article.quantity_available : @unit[i] %> * <%=h order_article.article.unit %></td>
<td><%= number_to_currency(@price[i]) %></td>
<td id="units_<%= i %>"><%= order_article.units_to_order %></td>
<td style="text-align:right;">
<input type="hidden" id="q_<%= i %>" name="<%= "ordered[#{order_article.id}][quantity]" %>" value="<%= @quantity[i] %>" size="2" />
<span id="q_used_<%= i %>" class="used"><%= @used_quantity[i] %></span> +
<span id="q_unused_<%= i %>" class="unused"><%= @quantity[i] - @used_quantity[i] %></span>
<span class="total">(<span id="q_total_<%= i %>"><%= @quantity[i] + @others_quantity[i] %></span>)</span>
<%= button_to_function('+', "increaseQuantity(#{i})") %>
<%= button_to_function('-', "decreaseQuantity(#{i})") %>
</td>
<td style="text-align:right;">
<input type="hidden" id="t_<%= i %>" name="<%= "ordered[#{order_article.id}][tolerance]" %>" value="<%= @tolerance[i] %>" size="2" />
<% if (@unit[i] > 1) -%>
<span id="t_used_<%= i %>" class="used"><%= @used_tolerance[i] %></span> +
<span id="t_unused_<%= i %>" class="unused"><%= @tolerance[i] - @used_tolerance[i] %></span>
<span class="total">(<span id="t_total_<%= i %>"><%= @tolerance[i] + @others_tolerance[i] %></span>)</span>
<%= button_to_function('+', "increaseTolerance(#{i})") %>
<%= button_to_function('-', "decreaseTolerance(#{i})") %>
<% end -%>
</td>
<td id="td_price_<%= i %>" style="text-align:right; padding-right:10px; width:4em"><span id="price_<%= i %>_display"><%= number_to_currency(article_total, :unit => "") %></span> €</td>
</tr>
<% unless order_article.article.note.blank? -%>
<tr id="note_<%= i %>" class="note" style="display:none">
<td colspan="10"><%=h order_article.article.note %> | <%=h order_article.article.manufacturer %></td>
</tr>
<tr class="<%= cycle('even', 'odd', :name => 'articles') %>" valign="top">
<td class="name">
<% unless order_article.article.note.blank? %>
<%= order_article.article.name %> <%= image_tag "lamp_grey.png", {:alt => _("Show note"), :size => "15x16", :border => "0", :onmouseover => "$('note_#{i}').show();", :onmouseout => "$('note_#{i}').hide();" }%>
<% else %>
<%= order_article.article.name %>
<% end %>
</td>
<td><%=h order_article.article.origin %></td>
<td><%=h truncate order_article.article.manufacturer, :length => 11 %></td>
<td><%= @order.stockit? ? order_article.article.quantity_available : @unit[i] %> * <%=h order_article.article.unit %></td>
<td><%= number_to_currency(@price[i]) %></td>
<td id="units_<%= i %>"><%= order_article.units_to_order %></td>
<td style="text-align:right;">
<input type="hidden" id="q_<%= i %>" name="<%= "ordered[#{order_article.id}][quantity]" %>" value="<%= @quantity[i] %>" size="2" />
<span id="q_used_<%= i %>" class="used"><%= @used_quantity[i] %></span> +
<span id="q_unused_<%= i %>" class="unused"><%= @quantity[i] - @used_quantity[i] %></span>
<span class="total">(<span id="q_total_<%= i %>"><%= @quantity[i] + @others_quantity[i] %></span>)</span>
<%= button_to_function('+', "increaseQuantity(#{i})") %>
<%= button_to_function('-', "decreaseQuantity(#{i})") %>
</td>
<td style="text-align:right;">
<input type="hidden" id="t_<%= i %>" name="<%= "ordered[#{order_article.id}][tolerance]" %>" value="<%= @tolerance[i] %>" size="2" />
<% if (@unit[i] > 1) -%>
<span id="t_used_<%= i %>" class="used"><%= @used_tolerance[i] %></span> +
<span id="t_unused_<%= i %>" class="unused"><%= @tolerance[i] - @used_tolerance[i] %></span>
<span class="total">(<span id="t_total_<%= i %>"><%= @tolerance[i] + @others_tolerance[i] %></span>)</span>
<%= button_to_function('+', "increaseTolerance(#{i})") %>
<%= button_to_function('-', "decreaseTolerance(#{i})") %>
<% end -%>
</td>
<td id="td_price_<%= i %>" style="text-align:right; padding-right:10px; width:4em"><span id="price_<%= i %>_display"><%= number_to_currency(article_total, :unit => "") %></span> €</td>
</tr>
<% unless order_article.article.note.blank? -%>
<tr id="note_<%= i %>" class="note" style="display:none">
<td colspan="10"><%=h order_article.article.note %> | <%=h order_article.article.manufacturer %></td>
</tr>
<% end -%>
<%- i = i + 1
end
end -%>
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "Total amount" %>: <span id="total_price"><%= total %></span> €</td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "Credit available"%>: <%= number_to_currency(@availableFunds) %></td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "New account balance"%>: <strong><span id="new_balance"><%= @ordergroup.account_balance - total %></span> €</strong></td>
</tr>
<tr>
<td style="text-align:left;"><%= link_to_top %></td>
<td colspan="5"></td>
<td colspan="3" style="text-align:right;"><span style="font-size:1.2em"><%= submit_tag( _("Save order"), :id => 'submit_button' ) %></span> | <%= link_to _("Cancel"), :controller => 'ordering' %></td>
</tr>
</tfoot>
</table>
</div>
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "Total amount" %>: <span id="total_price"><%= total %></span> €</td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "Credit available"%>: <%= number_to_currency(@availableFunds) %></td>
</tr>
<tr>
<td colspan="6"></td>
<td colspan="3" class="currency"><%=_ "New account balance"%>: <strong><span id="new_balance"><%= @ordergroup.account_balance - total %></span> €</strong></td>
</tr>
<tr>
<td style="text-align:left;"><%= link_to_top %></td>
<td colspan="5"></td>
<td colspan="3" style="text-align:right;"><span style="font-size:1.2em"><%= submit_tag( _("Save order"), :id => 'submit_button' ) %></span> | <%= link_to _("Cancel"), :controller => 'ordering' %></td>
</tr>
</tfoot>
</table>
</div>
<input type="hidden" id="total_balance" name="total_balance" value="<%= @ordergroup.account_balance - total %>"/>
<input type="hidden" name="version" value="<%= @version %>"/>
<% end %>
@ -168,7 +108,7 @@
//<![CDATA[
// preset data
<% for i in 0...@price.size -%>
addData(<%= @price[i] %>, <%= @unit[i] %>, <%= @price[i] * (@tolerance[i] + @quantity[i])%>, <%= @others_quantity[i] %>, <%= @others_tolerance[i] %>, <%= @used_quantity[i] %>);
addData(<%= @price[i] %>, <%= @unit[i] %>, <%= @price[i] * (@tolerance[i] + @quantity[i])%>, <%= @others_quantity[i] %>, <%= @others_tolerance[i] %>, <%= @used_quantity[i] %>, 0);
<% end -%>
setGroupBalance(<%= @availableFunds %>);

View File

@ -0,0 +1,98 @@
= render :partial => 'order_head'
.single_column{:style => 'clear:both'}
- form_tag(:action => 'saveOrder', :id => @order) do
.box_title
%h2 Anderer Bestellungen
.column_content
%table#order.list
%thead
%tr
%th Name
%th
%th Herstellerin
%th Lieferantin
%th{:style => "width:5em;"} Einheit
%th{:style => "width:4.5em;"} Preis
%th Verfügbar
%th#col_required Menge
%th Summe
%tbody
- total = 0
- i = 0
- for category_name, order_articles in @articles_grouped_by_category
%tr{:style => "background-color:#EFEFEF"}
%td{:style => "text-align:left"}
%b=h category_name
%td{:colspan => "9"}
- for order_article in order_articles
- article_total = @price[i] * @quantity[i]
- total += article_total
%tr{:class => cycle('even', 'odd', :name => 'articles'), :valign => "top"}
%td.name
= order_article.article.name
- unless order_article.article.note.blank?
= image_tag "lamp_grey.png", {:alt => _("Show note"), :size => "15x16", :border => "0", :onmouseover => "$('note_#{i}').show();", :onmouseout => "$('note_#{i}').hide();" }
%td=h order_article.article.origin
%td=h truncate order_article.article.manufacturer, :length => 11
%td=h truncate order_article.article.supplier.name, :length => 11
%td=h order_article.article.unit
%td= number_to_currency @price[i]
%td= @quantity_available[i]
%td{:style => "text-align:right;"}
= hidden_field_tag "ordered[#{order_article.id}][quantity]", @quantity[i], :id => "q_#{i}", :size => "2"
%span.used{:id => "q_used_#{i}"}= @used_quantity[i]
%span.total= "(<span id='q_total_#{i}'>#{@quantity[i] + @others_quantity[i]}</span>)"
= button_to_function('+', "increaseStockQuantity(#{i})")
= button_to_function('-', "decreaseStockQuantity(#{i})")
%td{:id => "td_price_#{i}", :style => "text-align:right; padding-right:10px; width:4em"}
%span{:id => "price_#{i}_display"}= number_to_currency(article_total, :unit => "")
- unless order_article.article.note.blank?
%tr.note{:id => "note_#{i}", :style => "display:none"}
%td{:colspan => "10"}
=h order_article.article.note
|
=h order_article.article.manufacturer
- i = i + 1
%tfoot
%tr
%td{:colspan => "5"}
%td.currency{:colspan => "3"}
Gesamtbetrag:
%span#total_price= total
%tr
%td{:colspan => "5"}
%td.currency{:colspan => "3"}
Verfügbares Guthaben:
= number_to_currency @availableFunds
%tr
%td{:colspan => "5"}
%td.currency{:colspan => "3"}
Neuer Kontostand:
%strong
%span#new_balance= @ordergroup.account_balance - total
%tr
%td{:style => "text-align:left;"}= link_to_top
%td{:colspan => "4"}
%td{:colspan => "3", :style => "text-align:right;"}
%span{:style => "font-size:1.2em"}= submit_tag("Bestellung speichern", :id => 'submit_button' )
|
= link_to "Abbrechen", :controller => 'ordering'
= hidden_field_tag "total_balance", @ordergroup.account_balance - total, :id => "total_balance"
= hidden_field_tag "version", @version
%script{:type => "text/" + "javascript"}
// preset data
- for i in 0...@price.size
= "addData(#{@price[i]}, 1, #{@price[i] * @quantity[i]}, #{@others_quantity[i]}, 0, #{@used_quantity[i]}, #{@quantity_available[i]});"
= "setGroupBalance(#{@availableFunds});"
// localization
setDecimalSeparator(",");
// initialize javascript
updateBalance();

View File

@ -18,6 +18,7 @@
%th Einheit
%th Preis
%th Lieferant
%th Kategorie
%tbody
- for article in @articles
%tr{:class => cycle("even", "odd")}
@ -26,3 +27,4 @@
%td= article.unit
%td= article.price
%td= link_to article.supplier.name, article.supplier
%td= article.article_category.name

View File

@ -126,6 +126,8 @@ de:
article:
price: Nettopreis
gross_price: Bruttopreis
stock_article:
price: Nettopreis
user:
password: Passwort
first_name: Vorname

View File

@ -4,8 +4,6 @@ ActionController::Routing::Routes.draw do |map|
map.my_tasks '/home/tasks', :controller => 'tasks', :action => 'myTasks'
map.resources :orders, :member => { :finish => :post, :add_comment => :post }
map.resources :stock_orders, :member => { :finish => :post, :add_comment => :post },
:controller => 'orders'
map.resources :messages, :only => [:index, :show, :new, :create],
:member => { :reply => :get, :user => :get, :group => :get }
@ -22,7 +20,8 @@ ActionController::Routing::Routes.draw do |map|
end
map.resources :suppliers, :collection => { :shared_suppliers => :get } do |suppliers|
suppliers.resources :deliveries, :member => { :drop_stock_change => :post }
suppliers.resources :deliveries, :member => { :drop_stock_change => :post },
:collection => {:add_stock_article => :post}
suppliers.resources :articles,
:collection => { :update_selected => :post, :edit_all => :get, :update_all => :post,
:upload => :get, :parse_upload => :post, :create_from_upload => :post,

View File

@ -1,19 +0,0 @@
class CreateInvoices < ActiveRecord::Migration
def self.up
create_table :invoices do |t|
t.integer :supplier_id
t.integer :delivery_id
t.string :number
t.date :date
t.date :paid_on
t.text :note
t.decimal :amount, :null => false, :precision => 8, :scale => 2, :default => 0.0
t.timestamps
end
end
def self.down
drop_table :invoices
end
end

View File

@ -1,13 +0,0 @@
class CreateDeliveries < ActiveRecord::Migration
def self.up
create_table :deliveries do |t|
t.integer :supplier_id
t.date :delivered_on
t.datetime :created_at
end
end
def self.down
drop_table :deliveries
end
end

View File

@ -1,14 +0,0 @@
class CreateWorkgroups < ActiveRecord::Migration
def self.up
# Migrate all groups to workgroups
Group.find(:all, :conditions => { :type => "" }).each do |workgroup|
workgroup.update_attribute(:type, "Workgroup")
end
end
def self.down
Group.find(:all, :conditions => { :type => "Workgroup" }).each do |workgroup|
workgroup.update_attribute(:type, "")
end
end
end

View File

@ -1,16 +0,0 @@
class RenameOrdergroups < ActiveRecord::Migration
def self.up
rename_column :financial_transactions, :order_group_id, :ordergroup_id
rename_column :group_orders, :order_group_id, :ordergroup_id
rename_column :tasks, :group_id, :workgroup_id
remove_index :group_orders, :name => "index_group_orders_on_order_group_id_and_order_id"
add_index :group_orders, [:ordergroup_id, :order_id], :unique => true
Group.find(:all, :conditions => { :type => "OrderGroup" }).each do |ordergroup|
ordergroup.update_attribute(:type, "Ordergroup")
end
end
def self.down
end
end

View File

@ -1,20 +0,0 @@
class RefactorMessaging < ActiveRecord::Migration
def self.up
drop_table :messages
create_table :messages do |t|
t.references :sender
t.text :recipients_ids
t.string :subject, :null => false
t.text :body
t.integer :email_state, :default => 0, :null => false
t.boolean :private, :default => false
t.datetime :created_at
end
end
def self.down
end
end

View File

@ -1,17 +0,0 @@
class CreateStockChanges < ActiveRecord::Migration
def self.up
create_table :stock_changes do |t|
t.references :delivery
t.references :order
t.references :article
t.decimal :quantity, :precision => 6, :scale => 2, :default => 0.0
t.datetime :created_at
end
add_column :articles, :quantity, :decimal, :precision => 6, :scale => 2, :default => 0.0
end
def self.down
drop_table :stock_changes
end
end

View File

@ -1,11 +0,0 @@
class ActsAsParanoid < ActiveRecord::Migration
def self.up
add_column :suppliers, :deleted_at, :datetime
add_column :articles, :deleted_at, :datetime
end
def self.down
remove_column :suppliers, :deleted_at
remove_column :articles, :deleted_at
end
end

View File

@ -2,10 +2,42 @@ class RefactorOrderLogic < ActiveRecord::Migration
def self.up
# TODO: Combine migrations since foodsoft3-development into one file
# and try to build a migration path from old data.
# # == Message
# drop_table :messages
# create_table :messages do |t|
# t.references :sender
# t.text :recipients_ids
# t.string :subject, :null => false
# t.text :body
# t.integer :email_state, :default => 0, :null => false
# t.boolean :private, :default => false
# t.datetime :created_at
# end
#
# # Acts_as_paranoid
# add_column :suppliers, :deleted_at, :datetime
# add_column :articles, :deleted_at, :datetime
# add_column :groups, :deleted_at, :datetime
#
# # == Workgroups
# # Migrate all groups to workgroups
# Group.find(:all, :conditions => { :type => "" }).each do |workgroup|
# workgroup.update_attribute(:type, "Workgroup")
# end
#
# # == Ordergroups
# add_column :groups, :deleted_at, :datetime # acts_as_paranoid
# remove_column :groups, :actual_size # Useless, desposits are better stored within a transaction.note
# # rename from OrderGroup to Ordergroup
# rename_column :financial_transactions, :order_group_id, :ordergroup_id
# rename_column :group_orders, :order_group_id, :ordergroup_id
# rename_column :tasks, :group_id, :workgroup_id
# remove_index :group_orders, :name => "index_group_orders_on_order_group_id_and_order_id"
# add_index :group_orders, [:ordergroup_id, :order_id], :unique => true
#
# Group.find(:all, :conditions => { :type => "OrderGroup" }).each do |ordergroup|
# ordergroup.update_attribute(:type, "Ordergroup")
# end
# # move contact-infos from users to ordergroups
# add_column :groups, :contact_person, :string
# add_column :groups, :contact_phone, :string
@ -19,10 +51,6 @@ class RefactorOrderLogic < ActiveRecord::Migration
# end
# remove_column :users, :address
#
# # == Article
# rename_column :articles, :net_price, :price
# remove_column :articles, :gross_price
#
# # == Order
# drop_table :orders
# drop_table :group_order_results
@ -41,9 +69,26 @@ class RefactorOrderLogic < ActiveRecord::Migration
# end
#
# # == Invoice
# add_column :invoices, :order_id, :integer
# add_column :invoices, :deposit, :decimal, :precision => 8, :scale => 2, :default => 0.0, :null => false
# add_column :invoices, :deposit_credit, :decimal, :precision => 8, :scale => 2, :default => 0.0, :null => false
# create_table :invoices do |t|
# t.references :supplier
# t.references :delivery
# t.references :order
# t.string :number
# t.date :date
# t.date :paid_on
# t.text :note
# t.decimal :amount, :null => false, :precision => 8, :scale => 2, :default => 0.0
# t.decimal :deposit, :precision => 8, :scale => 2, :default => 0.0, :null => false
# t.decimal :deposit_credit, :precision => 8, :scale => 2, :default => 0.0, :null => false
# t.timestamps
# end
#
# # == Delivery
# create_table :deliveries do |t|
# t.integer :supplier_id
# t.date :delivered_on
# t.datetime :created_at
# end
#
# # == Comment
# drop_table :comments
@ -54,6 +99,10 @@ class RefactorOrderLogic < ActiveRecord::Migration
# t.datetime :created_at
# end
#
# # == Article
# rename_column :articles, :net_price, :price
# remove_column :articles, :gross_price
#
# # == ArticlePrice
# create_table :article_prices do |t|
# t.references :article
@ -81,6 +130,22 @@ class RefactorOrderLogic < ActiveRecord::Migration
# # == GroupOrderArticle
# # The total order result in ordergroup is now saved!
# add_column :group_order_articles, :result, :integer, :default => nil
#
# # == StockArticle
# add_column :articles, :type, :string
# add_column :articles, :quantity, :integer, :default => 0
#
# # == StockChanges
# create_table :stock_changes do |t|
# t.references :delivery
# t.references :order
# t.references :stock_article
# t.integer :quantity, :default => 0
# t.datetime :created_at
# end
end
def self.down

View File

@ -46,6 +46,7 @@ ActiveRecord::Schema.define(:version => 20090119155930) do
t.datetime "updated_at"
t.decimal "quantity", :default => 0.0
t.datetime "deleted_at"
t.string "type"
end
add_index "articles", ["name", "supplier_id"], :name => "index_articles_on_name_and_supplier_id"
@ -212,8 +213,8 @@ ActiveRecord::Schema.define(:version => 20090119155930) do
create_table "stock_changes", :force => true do |t|
t.integer "delivery_id"
t.integer "order_id"
t.integer "article_id"
t.decimal "quantity", :precision => 6, :scale => 2, :default => 0.0
t.integer "stock_article_id"
t.decimal "quantity", :default => 0.0
t.datetime "created_at"
end

View File

@ -16,6 +16,7 @@ var itemTotal = new Array(); // total item price
var quantityOthers = new Array();
var toleranceOthers = new Array();
var itemsAllocated = new Array(); // how many items the group has been allocated and should definitely get
var quantityAvailable = new Array(); // stock_order. how many items are currently in stock
function setDecimalSeparator(character) {
decimalSeparator = character;
@ -25,7 +26,7 @@ function setGroupBalance(amount) {
groupBalance = amount;
}
function addData(itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated) {
function addData(itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemToleranceOthers, allocated, available) {
i = price.length;
price[i] = itemPrice;
unit[i] = itemUnit;
@ -33,6 +34,7 @@ function addData(itemPrice, itemUnit, itemSubtotal, itemQuantityOthers, itemTole
quantityOthers[i] = itemQuantityOthers;
toleranceOthers[i] = itemToleranceOthers;
itemsAllocated[i] = allocated;
quantityAvailable[i] = available;
}
function increaseQuantity(item) {
@ -103,6 +105,46 @@ function update(item, quantity, tolerance) {
updateBalance();
}
function increaseStockQuantity(item) {
value = Number($('q_' + item).value) + 1;
if (value <= quantityAvailable[item] - quantityOthers[item]) {
updateStockQuantity(item, value);
}
}
function decreaseStockQuantity(item) {
value = Number($('q_' + item).value) - 1;
if (value >= 0) {
updateStockQuantity(item, value);
}
}
function updateStockQuantity(item, quantity) {
// set modification flag
modified = true
// update hidden input fields
$('q_' + item).value = quantity;
// update used/unused quantity
available = Math.max(0, quantityAvailable[item] - quantityOthers[item]);
q_used = Math.min(available, quantity);
// ensure that at least the amout of items this group has already been allocated is used
if (quantity >= itemsAllocated[item] && q_used < itemsAllocated[item]) {
q_used = itemsAllocated[item];
}
$('q_used_' + item).update(String(q_used));
$('q_total_' + item).update(String(Number(quantity) + quantityOthers[item]));
// update total price
itemTotal[item] = price[item] * (Number(quantity));
$('price_' + item + '_display').update(asMoney(itemTotal[item]));
// update balance
updateBalance();
}
function asMoney(amount) {
return String(amount.toFixed(2)).replace(/\./, ",");
}

View File

@ -22,6 +22,7 @@
# updated_at :datetime
# quantity :decimal(, ) default(0.0)
# deleted_at :datetime
# type :string(255)
#
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

View File

@ -1,14 +1,14 @@
# == Schema Information
# Schema version: 20090119155930
# Schema version: 20090120184410
#
# Table name: stock_changes
#
# id :integer not null, primary key
# delivery_id :integer
# order_id :integer
# article_id :integer
# quantity :decimal(6, 2) default(0.0)
# created_at :datetime
# id :integer not null, primary key
# delivery_id :integer
# order_id :integer
# stock_article_id :integer
# quantity :decimal(, ) default(0.0)
# created_at :datetime
#
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

View File

@ -0,0 +1,8 @@
require 'test_helper'
class StockArticleTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end