Merge remote-tracking branch 'foodcoops/master' into feature-i18n-cleanup
Conflicts: app/views/deliveries/_stock_article_form.html.haml config/locales/de.yml config/locales/en.yml
This commit is contained in:
commit
94b2c8eac3
49 changed files with 656 additions and 358 deletions
|
@ -3,6 +3,7 @@ rvm:
|
|||
- 1.9.3
|
||||
services:
|
||||
- redis-server
|
||||
env: COVERALLS=1
|
||||
before_install:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
|
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Foodsoft 3.2.0
|
||||
(16 December 2013)
|
||||
|
||||
It's been a year since the previous release. Much has changed. Big changes have been:
|
||||
* Translations to English, Dutch and French.
|
||||
* Improved usability of delivery creation.
|
||||
* The possibility to extend foodsoft with plugins (the wiki is now optional).
|
||||
* Article search in the ordering screen.
|
||||
* Foodcoops can choose to use full names and emails instead of nicknames.
|
||||
* Foodcoops that don't use prepaid can set their minimum ordergroup balance below zero.
|
||||
* Group and article PDFs now show articles ordered but not received in grey.
|
||||
* Upgrade to Rails 3.
|
||||
|
||||
When you upgrade, be sure to review `config/app_config.yml.SAMPLE`. When you're running multiple foodcoops from a single installation, check your rake invocations as the syntax is now: `rake multicoops:run TASK=db:migrate`.
|
||||
|
||||
# Foodsoft 3.1.1
|
||||
(20 July 2012)
|
4
Gemfile
4
Gemfile
|
@ -84,10 +84,12 @@ group :test do
|
|||
# webkit and poltergeist don't seem to work yet
|
||||
gem 'selenium-webdriver'
|
||||
gem 'database_cleaner'
|
||||
gem 'simplecov', require: false
|
||||
# need to include rspec components before i18n-spec or rake fails in test environment
|
||||
gem 'rspec-core'
|
||||
gem 'rspec-expectations'
|
||||
gem 'rspec-rerun'
|
||||
gem 'i18n-spec'
|
||||
# code coverage
|
||||
gem 'simplecov', require: false
|
||||
gem 'coveralls', require: false
|
||||
end
|
||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -102,6 +102,12 @@ GEM
|
|||
execjs
|
||||
coffee-script-source (1.6.3)
|
||||
commonjs (0.2.7)
|
||||
coveralls (0.7.0)
|
||||
multi_json (~> 1.3)
|
||||
rest-client
|
||||
simplecov (>= 0.7)
|
||||
term-ansicolor
|
||||
thor
|
||||
daemons (1.1.9)
|
||||
database_cleaner (1.2.0)
|
||||
debug_inspector (0.0.2)
|
||||
|
@ -248,6 +254,8 @@ GEM
|
|||
redis-namespace (~> 1.2)
|
||||
sinatra (>= 0.9.2)
|
||||
vegas (~> 0.1.2)
|
||||
rest-client (1.6.7)
|
||||
mime-types (>= 1.16)
|
||||
rspec (2.14.1)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
|
@ -306,6 +314,8 @@ GEM
|
|||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.8)
|
||||
term-ansicolor (1.2.2)
|
||||
tins (~> 0.8)
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
|
@ -315,6 +325,7 @@ GEM
|
|||
rack (>= 1.0.0)
|
||||
thor (0.18.1)
|
||||
tilt (1.4.1)
|
||||
tins (0.13.1)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
|
@ -357,6 +368,7 @@ DEPENDENCIES
|
|||
client_side_validations
|
||||
client_side_validations-simple_form
|
||||
coffee-rails (~> 3.2.1)
|
||||
coveralls
|
||||
daemons
|
||||
database_cleaner
|
||||
exception_notification
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
3.1.1
|
||||
3.2.0
|
||||
|
|
|
@ -104,6 +104,10 @@ table {
|
|||
td.odd {
|
||||
background-color: @tableBackgroundAccent;
|
||||
}
|
||||
|
||||
td.main_info {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr.selected td {
|
||||
background-color: @successBackground;
|
||||
|
@ -247,3 +251,40 @@ tr.unavailable {
|
|||
.modal form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// multiple-column layout in forms (landscape tablet and wider only)
|
||||
@media (min-width: 768px) {
|
||||
.form-horizontal .fold-line {
|
||||
.control-group {
|
||||
float: left;
|
||||
}
|
||||
.control-group + .control-group {
|
||||
.control-label {
|
||||
width: auto;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.controls {
|
||||
float: left;
|
||||
margin-left: 0;
|
||||
}
|
||||
// fix margin somehow off
|
||||
// XXX there must be a better way
|
||||
margin-bottom: 0;
|
||||
.help-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.control-group:last-child {
|
||||
float: none;
|
||||
.controls {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// allow to have indicator text instead of input with same markup
|
||||
.control-text {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,57 +50,22 @@ class DeliveriesController < ApplicationController
|
|||
redirect_to supplier_deliveries_url(@supplier)
|
||||
end
|
||||
|
||||
# three possibilites to fill a new_stock_article form
|
||||
# (1) start from blank or use params
|
||||
def new_stock_article
|
||||
@stock_article = @supplier.stock_articles.build(params[:stock_article])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
# (2) StockArticle as template
|
||||
def copy_stock_article
|
||||
@stock_article = StockArticle.find(params[:old_stock_article_id]).dup
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
# (3) non-stock Article as template
|
||||
def derive_stock_article
|
||||
@stock_article = Article.find(params[:old_article_id]).becomes(StockArticle).dup
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def create_stock_article
|
||||
@stock_article = StockArticle.new(params[:stock_article])
|
||||
|
||||
if @stock_article.valid? and @stock_article.save
|
||||
render :layout => false
|
||||
else
|
||||
render :action => 'new_stock_article', :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
def edit_stock_article
|
||||
@stock_article = StockArticle.find(params[:stock_article_id])
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def update_stock_article
|
||||
@stock_article = StockArticle.find(params[:stock_article][:id])
|
||||
|
||||
if @stock_article.update_attributes(params[:stock_article])
|
||||
render :layout => false
|
||||
else
|
||||
render :action => 'edit_stock_article', :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
def add_stock_change
|
||||
@stock_change = StockChange.new
|
||||
@stock_change.stock_article = StockArticle.find(params[:stock_article_id])
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def form_on_stock_article_create # See publish/subscribe design pattern in /doc.
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def form_on_stock_article_update # See publish/subscribe design pattern in /doc.
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -4,30 +4,62 @@ class StockitController < ApplicationController
|
|||
@stock_articles = StockArticle.undeleted.includes(:supplier, :article_category).
|
||||
order('suppliers.name, article_categories.name, articles.name')
|
||||
end
|
||||
|
||||
def index_on_stock_article_create # See publish/subscribe design pattern in /doc.
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def index_on_stock_article_update # See publish/subscribe design pattern in /doc.
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
# three possibilites to fill a new_stock_article form
|
||||
# (1) start from blank or use params
|
||||
def new
|
||||
@stock_article = StockArticle.new
|
||||
@stock_article = StockArticle.new(params[:stock_article])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
# (2) StockArticle as template
|
||||
def copy
|
||||
@stock_article = StockArticle.find(params[:stock_article_id]).dup
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
# (3) non-stock Article as template
|
||||
def derive
|
||||
@stock_article = Article.find(params[:old_article_id]).becomes(StockArticle).dup
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def create
|
||||
@stock_article = StockArticle.new(params[:stock_article])
|
||||
if @stock_article.save
|
||||
redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_create.notice')
|
||||
if @stock_article.valid? and @stock_article.save
|
||||
render :layout => false
|
||||
else
|
||||
render :action => 'new'
|
||||
render :action => 'new', :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def update
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
if @stock_article.update_attributes(params[:stock_article])
|
||||
redirect_to stock_articles_path, :notice => I18n.t('stockit.stock_update.notice')
|
||||
render :layout => false
|
||||
else
|
||||
render :action => 'edit'
|
||||
render :action => 'edit', :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,9 +68,15 @@ class StockitController < ApplicationController
|
|||
@stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC')
|
||||
end
|
||||
|
||||
def show_on_stock_article_update # See publish/subscribe design pattern in /doc.
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def destroy
|
||||
@article = StockArticle.find(params[:id])
|
||||
@article.mark_as_deleted
|
||||
@stock_article = StockArticle.find(params[:id])
|
||||
@stock_article.mark_as_deleted
|
||||
render :layout => false
|
||||
rescue => error
|
||||
render :partial => "destroy_fail", :layout => false,
|
||||
|
|
|
@ -25,13 +25,4 @@ module DeliveriesHelper
|
|||
return output.html_safe
|
||||
end
|
||||
|
||||
def stock_article_price_hint(stock_article)
|
||||
t('simple_form.hints.stock_article.edit_stock_article.price',
|
||||
:stock_article_copy_link => link_to(t('.copy_stock_article'),
|
||||
copy_stock_article_supplier_deliveries_path(@supplier, :old_stock_article_id => stock_article.id),
|
||||
:remote => true
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -14,4 +14,13 @@ module StockitHelper
|
|||
link_to StockTaking.model_name.human, stock_taking_path(stock_change.stock_taking)
|
||||
end
|
||||
end
|
||||
|
||||
def stock_article_price_hint(stock_article)
|
||||
t('simple_form.hints.stock_article.edit_stock_article.price',
|
||||
:stock_article_copy_link => link_to(t('.copy_stock_article'),
|
||||
stock_article_copy_path(stock_article),
|
||||
:remote => true
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -101,49 +101,51 @@ class GroupOrderArticle < ActiveRecord::Base
|
|||
# See description of the ordering algorithm in the general application documentation for details.
|
||||
def calculate_result
|
||||
@calculate_result ||= begin
|
||||
quantity = tolerance = 0
|
||||
stockit = order_article.article.is_a?(StockArticle)
|
||||
quantity = tolerance = total_quantity = 0
|
||||
|
||||
# Get total
|
||||
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 order_article.article.is_a?(StockArticle)
|
||||
total = order_article.article.quantity
|
||||
logger.debug "<#{order_article.article.name}> (stock) => #{total}"
|
||||
else
|
||||
total = order_article.units_to_order * order_article.price.unit_quantity
|
||||
logger.debug "<#{order_article.article.name}> units_to_order #{order_article.units_to_order} => #{total}"
|
||||
end
|
||||
|
||||
if (total > 0)
|
||||
if total > 0
|
||||
# In total there are enough units ordered. Now check the individual result for the ordergroup (group_order).
|
||||
#
|
||||
# Get all GroupOrderArticleQuantities for this OrderArticle...
|
||||
order_quantities = GroupOrderArticleQuantity.all(
|
||||
:conditions => ["group_order_article_id IN (?)", order_article.group_order_article_ids], :order => 'created_on')
|
||||
logger.debug("GroupOrderArticleQuantity records found: #{order_quantities.size}")
|
||||
logger.debug "GroupOrderArticleQuantity records found: #{order_quantities.size}"
|
||||
|
||||
# Determine quantities to be ordered...
|
||||
total_quantity = i = 0
|
||||
while (i < order_quantities.size && total_quantity < total)
|
||||
q = (order_quantities[i].quantity <= total - total_quantity ? order_quantities[i].quantity : total - total_quantity)
|
||||
order_quantities.each do |goaq|
|
||||
q = [goaq.quantity, total - total_quantity].min
|
||||
total_quantity += q
|
||||
if (order_quantities[i].group_order_article_id == self.id)
|
||||
logger.debug("increasing quantity by #{q}")
|
||||
if goaq.group_order_article_id == self.id
|
||||
logger.debug "increasing quantity by #{q}"
|
||||
quantity += q
|
||||
end
|
||||
i += 1
|
||||
break if total_quantity >= total
|
||||
end
|
||||
|
||||
# Determine tolerance to be ordered...
|
||||
if (total_quantity < total)
|
||||
logger.debug("determining additional items to be ordered from tolerance")
|
||||
i = 0
|
||||
while (i < order_quantities.size && total_quantity < total)
|
||||
q = (order_quantities[i].tolerance <= total - total_quantity ? order_quantities[i].tolerance : total - total_quantity)
|
||||
if total_quantity < total
|
||||
logger.debug "determining additional items to be ordered from tolerance"
|
||||
order_quantities.each do |goaq|
|
||||
q = [goaq.tolerance, total - total_quantity].min
|
||||
total_quantity += q
|
||||
if (order_quantities[i].group_order_article_id == self.id)
|
||||
logger.debug("increasing tolerance by #{q}")
|
||||
if goaq.group_order_article_id == self.id
|
||||
logger.debug "increasing tolerance by #{q}"
|
||||
tolerance += q
|
||||
end
|
||||
i += 1
|
||||
break if total_quantity >= total
|
||||
end
|
||||
end
|
||||
|
||||
logger.debug("determined quantity/tolerance/total: #{quantity} / #{tolerance} / #{quantity + tolerance}")
|
||||
logger.debug "determined quantity/tolerance/total: #{quantity} / #{tolerance} / #{quantity + tolerance}"
|
||||
end
|
||||
|
||||
{:quantity => quantity, :tolerance => tolerance, :total => quantity + tolerance}
|
||||
|
|
|
@ -7,20 +7,51 @@
|
|||
.modal-body
|
||||
= f.input :availability
|
||||
= f.input :name
|
||||
= f.input :origin
|
||||
= f.input :manufacturer
|
||||
= f.input :unit
|
||||
.fold-line
|
||||
= f.input :unit_quantity, label: Article.human_attribute_name(:unit),
|
||||
input_html: {class: 'input-mini', title: Article.human_attribute_name(:unit_quantity)}
|
||||
= f.input :unit, label: '×'.html_safe,
|
||||
input_html: {class: 'input-mini', title: Article.human_attribute_name(:unit)}
|
||||
|
||||
= f.input :note
|
||||
= f.association :article_category
|
||||
/ TODO labels
|
||||
|
||||
= f.input :price
|
||||
= f.input :unit_quantity
|
||||
.fold-line
|
||||
= f.input :price do
|
||||
.input-prepend
|
||||
%span.add-on= t 'number.currency.format.unit'
|
||||
= f.input_field :price, class: 'input-mini'
|
||||
= f.input :tax do
|
||||
.input-append
|
||||
= f.input_field :tax, class: 'input-mini'
|
||||
%span.add-on %
|
||||
.fold-line
|
||||
= f.input :deposit do
|
||||
.input-prepend
|
||||
%span.add-on= t 'number.currency.format.unit'
|
||||
= f.input_field :deposit, class: 'input-mini'
|
||||
.control-group
|
||||
%label.control-label{for: 'article_fc_price'}
|
||||
= Article.human_attribute_name(:fc_price)
|
||||
.controls.control-text#article_fc_price
|
||||
= number_to_currency(@article.fc_price) rescue nil
|
||||
|
||||
= f.input :origin
|
||||
= f.input :manufacturer
|
||||
= f.input :order_number
|
||||
= f.input :tax, :wrapper => :append do
|
||||
= f.input_field :tax
|
||||
%span.add-on %
|
||||
= f.input :deposit
|
||||
.modal-footer
|
||||
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
|
||||
= f.submit class: 'btn btn-primary'
|
||||
|
||||
:javascript
|
||||
var form = $('form.edit_article, form.new_article');
|
||||
$('#article_price, #article_tax, #article_deposit', form).on('change keyup', function() {
|
||||
var price = parseFloat($('#article_price', form).val());
|
||||
var tax = parseFloat($('#article_tax', form).val());
|
||||
var deposit = parseFloat($('#article_deposit', form).val());
|
||||
// Article#gross_price and Article#fc_price
|
||||
var gross_price = (price + deposit) * (tax / 100 + 1);
|
||||
var fc_price = gross_price * (#{FoodsoftConfig[:price_markup].to_f} / 100 + 1);
|
||||
$('#article_fc_price').html($.isNumeric(fc_price) ? I18n.l("currency", fc_price) : '…');
|
||||
});
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
}
|
||||
if('new' == selectedArticle.id) {
|
||||
$.ajax({
|
||||
url: '#{new_stock_article_supplier_deliveries_path(@supplier)}',
|
||||
url: '#{new_stock_article_path}',
|
||||
type: 'get',
|
||||
data: {stock_article: {name: selectedArticle.text}},
|
||||
data: {stock_article: {name: selectedArticle.text, supplier_id: #{@supplier.id}}},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
$('#new_stock_article').select2('data', null);
|
||||
|
@ -52,7 +52,7 @@
|
|||
}
|
||||
if('' != selectedArticle.id) {
|
||||
$.ajax({
|
||||
url: '#{derive_stock_article_supplier_deliveries_path(@supplier)}',
|
||||
url: '#{derive_stock_articles_path}',
|
||||
type: 'get',
|
||||
data: {old_article_id: selectedArticle.id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
|
@ -61,6 +61,26 @@
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Subscribe to database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).on('StockArticle#create', function(e) {
|
||||
$.ajax({
|
||||
url: '#{form_on_stock_article_create_supplier_deliveries_path(@supplier)}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('StockArticle#update', function(e) {
|
||||
$.ajax({
|
||||
url: '#{form_on_stock_article_update_supplier_deliveries_path(@supplier)}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function mark_article_for_delivery(stock_article_id) {
|
||||
|
@ -96,7 +116,7 @@
|
|||
%tr
|
||||
%th{:colspan => 5}
|
||||
- if articles_for_select2(@supplier).empty?
|
||||
= link_to t('.create_stock_article'), new_stock_article_supplier_deliveries_path(@supplier), :remote => true, :class => 'btn'
|
||||
= link_to t('.create_stock_article'), new_stock_article_path, :remote => true, :class => 'btn'
|
||||
- else
|
||||
%input#new_stock_article{:style => 'width: 500px;'}
|
||||
%tbody
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
- css_class = ( @delivery and @delivery.includes_article? article ) ? ( 'unavailable' ) : ( false )
|
||||
- disable_delivery_action = ( @delivery and @delivery.includes_article? article )
|
||||
- css_class = ( disable_delivery_action ) ? ( 'unavailable' ) : ( false )
|
||||
- deliver_button_disabled = ( disable_delivery_action ) ? ( 'disabled' ) : ( false )
|
||||
|
||||
%tr{:id => "stock_article_#{article.id}", :class => css_class}
|
||||
%td= article.name
|
||||
%td{:data => {:toggle => :tooltip, :title => render(:partial => 'shared/article_price_info', :locals => {:article => article})}}= number_to_currency article.price
|
||||
%td= article.unit
|
||||
%td= article.article_category.name
|
||||
%td
|
||||
= link_to t('.action_edit'), edit_stock_article_supplier_deliveries_path(@supplier, :stock_article_id => article.id), remote: true, class: 'btn btn-mini'
|
||||
= link_to t('.action_other_price'), copy_stock_article_supplier_deliveries_path(@supplier, :old_stock_article_id => article.id), remote: true, class: 'btn btn-mini'
|
||||
- deliver_button_disabled = ( @delivery and @delivery.includes_article? article ) ? ( 'disabled' ) : ( false )
|
||||
= link_to t('.action_edit'), edit_stock_article_path(article), remote: true, class: 'btn btn-mini'
|
||||
= link_to t('.action_other_price'), stock_article_copy_path(article), remote: true, class: 'btn btn-mini'
|
||||
= link_to t('.action_add_to_delivery'), add_stock_change_supplier_deliveries_path(@supplier, :stock_article_id => article.id), :method => :post, remote: true, class: 'button-add-stock-change btn btn-mini btn-primary', disabled: deliver_button_disabled
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
- url = ( stock_article.new_record? ) ? ( create_stock_article_supplier_deliveries_path(@supplier) ) : ( update_stock_article_supplier_deliveries_path(@supplier) )
|
||||
= simple_form_for stock_article, url: url, remote: true, validate: true do |f|
|
||||
= f.association :supplier, :as => :hidden
|
||||
= f.hidden_field :id unless stock_article.new_record?
|
||||
.modal-header
|
||||
= link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
|
||||
%h3= t 'activerecord.models.stock_article'
|
||||
.modal-body
|
||||
= f.input :name
|
||||
= f.input :unit
|
||||
= f.input :note
|
||||
- if stock_article.new_record?
|
||||
= f.input :price
|
||||
= f.input :tax, :wrapper => :append do
|
||||
= f.input_field :tax
|
||||
%span.add-on %
|
||||
= f.input :deposit
|
||||
- else
|
||||
= f.input :price, :input_html => {:disabled => 'disabled'}, :hint => stock_article_price_hint(stock_article).html_safe
|
||||
= f.association :article_category
|
||||
.modal-footer
|
||||
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
|
||||
= f.submit :class => 'btn btn-primary', 'data-disable-with' => t('ui.please_wait')
|
|
@ -1,5 +0,0 @@
|
|||
$('#modalContainer').html(
|
||||
'<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>'
|
||||
);
|
||||
|
||||
$('#modalContainer').modal();
|
|
@ -1,16 +0,0 @@
|
|||
$('div.container-fluid').prepend(
|
||||
'<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @stock_article.name)})) %>'
|
||||
);
|
||||
|
||||
(function() {
|
||||
$('#stock_articles_for_adding tr').removeClass('success');
|
||||
|
||||
var stock_article_for_adding = $(
|
||||
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>'
|
||||
).addClass('success');
|
||||
|
||||
$('#stock_articles_for_adding tbody').append(stock_article_for_adding);
|
||||
updateSort('#stock_articles_for_adding');
|
||||
})();
|
||||
|
||||
$('#modalContainer').modal('hide');
|
|
@ -1,5 +0,0 @@
|
|||
$('#modalContainer').html(
|
||||
'<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>'
|
||||
);
|
||||
|
||||
$('#modalContainer').modal();
|
|
@ -1,5 +0,0 @@
|
|||
$('#modalContainer').html(
|
||||
'<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>'
|
||||
);
|
||||
|
||||
$('#modalContainer').modal();
|
31
app/views/deliveries/form_on_stock_article_create.js.erb
Normal file
31
app/views/deliveries/form_on_stock_article_create.js.erb
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function(w) {
|
||||
|
||||
$('#stock_articles_for_adding tr').removeClass('success');
|
||||
|
||||
if(<%= @supplier.id != @stock_article.supplier.id %>) {
|
||||
// the stock_article does _NOT_ belong to the current supplier
|
||||
var try_again = w.confirm('<%= j(
|
||||
t('deliveries.form.confirm_foreign_supplier_reedit', :name => @stock_article.name)
|
||||
) %>');
|
||||
|
||||
if(try_again) {
|
||||
$.ajax({
|
||||
url: '<%= j edit_stock_article_path(@stock_article) %>',
|
||||
type: 'get',
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// the stock_article _DOES_ belong to the current supplier
|
||||
var stock_article_for_adding = $(
|
||||
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>'
|
||||
).addClass('success');
|
||||
|
||||
$('#stock_articles_for_adding tbody').append(stock_article_for_adding);
|
||||
updateSort('#stock_articles_for_adding');
|
||||
})(window);
|
47
app/views/deliveries/form_on_stock_article_update.js.erb
Normal file
47
app/views/deliveries/form_on_stock_article_update.js.erb
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function(w) {
|
||||
// update entry in stock_article table
|
||||
|
||||
$('#stock_articles_for_adding tr').removeClass('success');
|
||||
|
||||
$('#stock_article_<%= @stock_article.id %>').remove();
|
||||
|
||||
if(<%= @supplier.id != @stock_article.supplier.id %>) {
|
||||
// the stock_article does _NOT_ belong to the current supplier
|
||||
var try_again = w.confirm('<%= j(
|
||||
t('deliveries.form.confirm_foreign_supplier_reedit', :name => @stock_article.name)
|
||||
) %>');
|
||||
|
||||
if(try_again) {
|
||||
$.ajax({
|
||||
url: '<%= j edit_stock_article_path(@stock_article) %>',
|
||||
type: 'get',
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the stock_article _DOES_ belong to the current supplier
|
||||
var stock_article_for_adding = $(
|
||||
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>'
|
||||
).addClass('success');
|
||||
|
||||
$('#stock_articles_for_adding tbody').append(stock_article_for_adding);
|
||||
updateSort('#stock_articles_for_adding');
|
||||
}
|
||||
|
||||
mark_article_for_delivery(<%= @stock_article.id %>);
|
||||
|
||||
// update entry in stock_changes table
|
||||
|
||||
$('#stock_changes tr').removeClass('success');
|
||||
|
||||
var stock_change_entry = $('#stock_change_stock_article_<%= @stock_article.id %>');
|
||||
$('.stock_article_name', stock_change_entry).text('<%= j(@stock_article.name) %>');
|
||||
$('.unit', stock_change_entry).text('<%= j(@stock_article.unit) %>');
|
||||
|
||||
stock_change_entry.addClass('success');
|
||||
|
||||
updateSort('#stock_changes');
|
||||
})(window);
|
|
@ -1,5 +0,0 @@
|
|||
$('#modalContainer').html(
|
||||
'<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>'
|
||||
);
|
||||
|
||||
$('#modalContainer').modal();
|
|
@ -1,32 +0,0 @@
|
|||
$('div.container-fluid').prepend(
|
||||
'<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @stock_article.name)})) %>'
|
||||
);
|
||||
|
||||
(function() {
|
||||
// update entry in stock_article table
|
||||
|
||||
$('#stock_articles_for_adding tr').removeClass('success');
|
||||
|
||||
var stock_article_for_adding = $(
|
||||
'<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article, :delivery => @delivery})) %>'
|
||||
).addClass('success');
|
||||
|
||||
$('#stock_article_<%= @stock_article.id %>').replaceWith(stock_article_for_adding);
|
||||
updateSort('#stock_articles_for_adding');
|
||||
|
||||
mark_article_for_delivery(<%= @stock_article.id %>);
|
||||
|
||||
// update entry in stock_changes table
|
||||
|
||||
$('#stock_changes tr').removeClass('success');
|
||||
|
||||
var stock_change_entry = $('#stock_change_stock_article_<%= @stock_article.id %>');
|
||||
$('.stock_article_name', stock_change_entry).text('<%= j(@stock_article.name) %>');
|
||||
$('.unit', stock_change_entry).text('<%= j(@stock_article.unit) %>');
|
||||
|
||||
stock_change_entry.addClass('success');
|
||||
|
||||
updateSort('#stock_changes');
|
||||
})();
|
||||
|
||||
$('#modalContainer').modal('hide');
|
|
@ -1,18 +1,21 @@
|
|||
= simple_form_for stock_article, :validate => true do |f|
|
||||
= f.association :supplier
|
||||
= f.input :name
|
||||
= f.input :unit
|
||||
= f.input :note
|
||||
|
||||
- if stock_article.new_record?
|
||||
= f.input :price
|
||||
= f.input :tax, :wrapper => :append do
|
||||
= f.input_field :tax
|
||||
%span.add-on %
|
||||
= f.input :deposit
|
||||
- else
|
||||
= f.input :price, :input_html => {:disabled => 'disabled'}, :hint => t('.price_hint')
|
||||
= f.association :article_category
|
||||
.form-actions
|
||||
= f.submit class: 'btn'
|
||||
= link_to t('ui.or_cancel'), stock_articles_path
|
||||
= simple_form_for stock_article, remote: true, :validate => true do |f|
|
||||
.modal-header
|
||||
= link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'}
|
||||
%h3= title
|
||||
.modal-body
|
||||
= f.association :supplier
|
||||
= f.input :name
|
||||
= f.input :unit
|
||||
= f.input :note
|
||||
- if stock_article.new_record?
|
||||
= f.input :price
|
||||
= f.input :tax, :wrapper => :append do
|
||||
= f.input_field :tax
|
||||
%span.add-on %
|
||||
= f.input :deposit
|
||||
- else
|
||||
= f.input :price, :input_html => {:disabled => 'disabled'}, :hint => stock_article_price_hint(stock_article).html_safe
|
||||
= f.association :article_category
|
||||
.modal-footer
|
||||
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
|
||||
= f.submit :class => 'btn btn-primary', 'data-disable-with' => t('ui.please_wait')
|
||||
|
|
14
app/views/stockit/_stock_article.html.haml
Normal file
14
app/views/stockit/_stock_article.html.haml
Normal file
|
@ -0,0 +1,14 @@
|
|||
%tr{:class => stock_article_classes(stock_article), :id => "stockArticle-#{stock_article.id}"}
|
||||
%td= link_to stock_article.name, stock_article
|
||||
%td= stock_article.quantity
|
||||
%td= stock_article.quantity_ordered
|
||||
%td.main_info= stock_article.quantity_available
|
||||
%td= stock_article.unit
|
||||
%td= stock_article.price
|
||||
%td= number_to_percentage stock_article.tax
|
||||
%td= link_to stock_article.supplier.name, stock_article.supplier
|
||||
%td= stock_article.article_category.name
|
||||
%td
|
||||
= link_to t('ui.edit'), edit_stock_article_path(stock_article), remote: true, class: 'btn btn-mini'
|
||||
= link_to t('ui.delete'), stock_article, :method => :delete, :confirm => t('.confirm_delete', :name => stock_article.name),
|
||||
class: 'btn btn-mini btn-danger', :remote => true
|
26
app/views/stockit/_stock_article_details.html.haml
Normal file
26
app/views/stockit/_stock_article_details.html.haml
Normal file
|
@ -0,0 +1,26 @@
|
|||
#stockArticleDetails
|
||||
%dl.dl-horizontal
|
||||
%dt= heading_helper(StockArticle, :supplier)
|
||||
%dd= link_to stock_article.supplier.name, stock_article.supplier
|
||||
%dt= heading_helper(StockArticle, :name)
|
||||
%dd= stock_article.name
|
||||
%dt= heading_helper(StockArticle, :unit)
|
||||
%dd= stock_article.unit
|
||||
%dt= heading_helper(StockArticle, :price)
|
||||
%dd= number_to_currency stock_article.price
|
||||
%dt= heading_helper(StockArticle, :tax)
|
||||
%dd= number_to_percentage stock_article.tax
|
||||
%dt= heading_helper(StockArticle, :deposit)
|
||||
%dd= number_to_currency stock_article.deposit
|
||||
%dt= heading_helper(StockArticle, :fc_price)
|
||||
%dd= number_to_currency stock_article.fc_price
|
||||
%dt= heading_helper(StockArticle, :article_category)
|
||||
%dd= stock_article.article_category.name
|
||||
%dt= heading_helper(StockArticle, :note)
|
||||
%dd= stock_article.note
|
||||
%dt= heading_helper(StockArticle, :quantity)
|
||||
%dd= stock_article.quantity
|
||||
%dt= heading_helper(StockArticle, :quantity_available)
|
||||
%dd= stock_article.quantity_available
|
||||
.form-actions
|
||||
= link_to t('ui.edit'), edit_stock_article_path(stock_article), remote: true, class: 'btn'
|
9
app/views/stockit/copy.js.erb
Normal file
9
app/views/stockit/copy.js.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
$('#modalContainer').html('<%= j(render(
|
||||
:partial => "form",
|
||||
:locals => {
|
||||
:title => t('.title'),
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>');
|
||||
|
||||
$('#modalContainer').modal();
|
15
app/views/stockit/create.js.erb
Normal file
15
app/views/stockit/create.js.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
$('div.container-fluid').prepend('<%= j(render(
|
||||
:partial => 'shared/alert_success',
|
||||
:locals => {
|
||||
:alert_message => t('.notice', :name => @stock_article.name)
|
||||
}
|
||||
)) %>');
|
||||
|
||||
// Publish database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).trigger({
|
||||
type: 'StockArticle#create',
|
||||
stock_article_id: <%= @stock_article.id %>
|
||||
});
|
||||
|
||||
$('#modalContainer').modal('hide');
|
9
app/views/stockit/derive.js.erb
Normal file
9
app/views/stockit/derive.js.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
$('#modalContainer').html('<%= j(render(
|
||||
:partial => "form",
|
||||
:locals => {
|
||||
:title => t('.title'),
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>');
|
||||
|
||||
$('#modalContainer').modal();
|
13
app/views/stockit/destroy.js.erb
Normal file
13
app/views/stockit/destroy.js.erb
Normal file
|
@ -0,0 +1,13 @@
|
|||
$('div.container-fluid').prepend('<%= j(render(
|
||||
:partial => 'shared/alert_success',
|
||||
:locals => {
|
||||
:alert_message => t('.notice', :name => @stock_article.name)
|
||||
}
|
||||
)) %>');
|
||||
|
||||
// Publish database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).trigger({
|
||||
type: 'StockArticle#destroy',
|
||||
stock_article_id: <%= @stock_article.id %>
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
-# please polish the following line if you know how, same in partial _destroy_fail
|
||||
var successDiv = $('<div class="alert fade in alert-success"><a class="close" data-dismiss="alert" href="#">#{escape_javascript(t('ui.marks.close').html_safe)}</a></div>');
|
||||
|
||||
successDiv.append(document.createTextNode('#{escape_javascript(t('.notice', name: @article.name))}'));
|
||||
$('div.container-fluid').prepend(successDiv);
|
||||
|
||||
$('#stockArticle-#{@article.id}').remove();
|
||||
-# WARNING: Do not use a simple .fadeOut() above, because it conflicts with the show/hide function of unavailable articles.
|
|
@ -1,3 +0,0 @@
|
|||
- title t('.title')
|
||||
|
||||
= render :partial => 'form', :locals => {:stock_article => @stock_article}
|
9
app/views/stockit/edit.js.erb
Normal file
9
app/views/stockit/edit.js.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
$('#modalContainer').html('<%= j(render(
|
||||
:partial => "form",
|
||||
:locals => {
|
||||
:title => t('.title'),
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>');
|
||||
|
||||
$('#modalContainer').modal();
|
|
@ -3,6 +3,30 @@
|
|||
:javascript
|
||||
$(function() {
|
||||
$('tr.unavailable').hide();
|
||||
|
||||
// Subscribe to database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).on('StockArticle#create', function(e) {
|
||||
$.ajax({
|
||||
url: '#{index_on_stock_article_create_stock_articles_path}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('StockArticle#destroy', function(e) {
|
||||
$('#stockArticle-' + e.stock_article_id).remove();
|
||||
});
|
||||
|
||||
$(document).on('StockArticle#update', function(e) {
|
||||
$.ajax({
|
||||
url: '#{index_on_stock_article_update_stock_articles_path}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
.well.well-small
|
||||
|
@ -17,7 +41,7 @@
|
|||
.btn-group
|
||||
= link_to_if @current_user.role_orders?, t('.order_online'), new_order_path(supplier_id: 0),
|
||||
class: 'btn', class: 'btn btn-primary'
|
||||
= link_to t('.new_stock_article'), new_stock_article_path, class: 'btn'
|
||||
= link_to t('.new_stock_article'), new_stock_article_path, remote: true, class: 'btn'
|
||||
= link_to t('.new_stock_taking'), new_stock_taking_path, class: 'btn'
|
||||
= link_to t('.show_stock_takings'), stock_takings_path, class: 'btn'
|
||||
|
||||
|
@ -42,22 +66,9 @@
|
|||
%th= heading_helper StockArticle, :supplier
|
||||
%th= heading_helper StockArticle, :article_category
|
||||
%th
|
||||
%tbody
|
||||
- for article in @stock_articles
|
||||
%tr{:class => stock_article_classes(article), :id => "stockArticle-#{article.id}"}
|
||||
%td= link_to article.name, article
|
||||
%td= article.quantity
|
||||
%td= article.quantity_ordered
|
||||
%th= article.quantity_available
|
||||
%td= article.unit
|
||||
%td= article.price
|
||||
%td= number_to_percentage article.tax
|
||||
%td= link_to article.supplier.name, article.supplier
|
||||
%td= article.article_category.name
|
||||
%td
|
||||
= link_to t('ui.edit'), edit_stock_article_path(article), class: 'btn btn-mini'
|
||||
= link_to t('ui.delete'), article, :method => :delete, :confirm => t('.confirm_delete'),
|
||||
class: 'btn btn-mini btn-danger', :remote => true
|
||||
%tbody#articles-tbody
|
||||
- for stock_article in @stock_articles
|
||||
= render :partial => 'stock_article', :locals => {:stock_article => stock_article}
|
||||
%p
|
||||
= t '.stock_worth'
|
||||
= number_to_currency StockArticle.stock_value
|
||||
|
|
14
app/views/stockit/index_on_stock_article_create.js.erb
Normal file
14
app/views/stockit/index_on_stock_article_create.js.erb
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function() {
|
||||
$('#articles-tbody tr').removeClass('success');
|
||||
|
||||
var stock_article_row = $('<%= j(render(
|
||||
:partial => 'stock_article',
|
||||
:locals => {
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>').addClass('success');
|
||||
|
||||
$('#articles-tbody').prepend(stock_article_row);
|
||||
})();
|
14
app/views/stockit/index_on_stock_article_update.js.erb
Normal file
14
app/views/stockit/index_on_stock_article_update.js.erb
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function() {
|
||||
$('#articles-tbody tr').removeClass('success');
|
||||
|
||||
var stock_article_row = $('<%= j(render(
|
||||
:partial => 'stock_article',
|
||||
:locals => {
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>').addClass('success');
|
||||
|
||||
$('#stockArticle-<%= @stock_article.id %>').replaceWith(stock_article_row);
|
||||
})();
|
|
@ -1,22 +0,0 @@
|
|||
- title t('.title')
|
||||
|
||||
- content_for :head do
|
||||
:javascript
|
||||
$(function() {
|
||||
$('#article_search').autocomplete({
|
||||
source: '#{articles_search_stock_articles_path}',
|
||||
select: function(e, ui) {
|
||||
alert(ui.item.value);
|
||||
//location.href = '#{nil}' + ui.item.value;
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
/
|
||||
TODO: Fix this
|
||||
%p
|
||||
= t '.search_text'
|
||||
= text_field_tag 'article_search'
|
||||
#stock_article_form
|
||||
= render :partial => 'form', :locals => {:stock_article => @stock_article}
|
9
app/views/stockit/new.js.erb
Normal file
9
app/views/stockit/new.js.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
$('#modalContainer').html('<%= j(render(
|
||||
:partial => "form",
|
||||
:locals => {
|
||||
:title => t('.title'),
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>');
|
||||
|
||||
$('#modalContainer').modal();
|
|
@ -1,32 +1,22 @@
|
|||
- title @stock_article.name
|
||||
- content_for :javascript do
|
||||
:javascript
|
||||
$(function() {
|
||||
// Subscribe to database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).on('StockArticle#update', function(e) {
|
||||
$.ajax({
|
||||
url: '#{show_on_stock_article_update_stock_articles_path}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
.row-fluid
|
||||
.span6
|
||||
%dl.dl-horizontal
|
||||
%dt= StockArticle.human_attribute_name 'supplier'
|
||||
%dd= link_to @stock_article.supplier.name, @stock_article.supplier
|
||||
%dt= StockArticle.human_attribute_name 'name'
|
||||
%dd= @stock_article.name
|
||||
%dt= StockArticle.human_attribute_name 'unit'
|
||||
%dd= @stock_article.unit
|
||||
%dt= StockArticle.human_attribute_name 'price'
|
||||
%dd= number_to_currency @stock_article.price
|
||||
%dt= StockArticle.human_attribute_name 'tax'
|
||||
%dd= number_to_percentage @stock_article.tax
|
||||
%dt= StockArticle.human_attribute_name 'deposit'
|
||||
%dd= number_to_currency @stock_article.deposit
|
||||
%dt= StockArticle.human_attribute_name 'fc_price'
|
||||
%dd= number_to_currency @stock_article.fc_price
|
||||
%dt= StockArticle.human_attribute_name 'article_category'
|
||||
%dd= @stock_article.article_category.name
|
||||
%dt= StockArticle.human_attribute_name 'note'
|
||||
%dd= @stock_article.note
|
||||
%dt= StockArticle.human_attribute_name 'quantity'
|
||||
%dd= @stock_article.quantity
|
||||
%dt= StockArticle.human_attribute_name 'quantity_available'
|
||||
%dd= @stock_article.quantity_available
|
||||
.form-actions
|
||||
= link_to t('ui.edit'), edit_stock_article_path(@stock_article), class: 'btn'
|
||||
= render :partial => 'stock_article_details', :locals => {:stock_article => @stock_article}
|
||||
|
||||
.span6
|
||||
%h2= t('.stock_changes')
|
||||
|
|
13
app/views/stockit/show_on_stock_article_update.js.erb
Normal file
13
app/views/stockit/show_on_stock_article_update.js.erb
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function() {
|
||||
var stock_article_details = $('<%= j(render(
|
||||
:partial => 'stock_article_details',
|
||||
:locals => {
|
||||
:stock_article => @stock_article
|
||||
}
|
||||
)) %>');
|
||||
|
||||
$('#stockArticleDetails').replaceWith(stock_article_details);
|
||||
$('h1').first().text('<%= j(@stock_article.name) %>');
|
||||
})();
|
15
app/views/stockit/update.js.erb
Normal file
15
app/views/stockit/update.js.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
$('div.container-fluid').prepend('<%= j(render(
|
||||
:partial => 'shared/alert_success',
|
||||
:locals => {
|
||||
:alert_message => t('.notice', :name => @stock_article.name)
|
||||
}
|
||||
)) %>');
|
||||
|
||||
// Publish database changes.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
$(document).trigger({
|
||||
type: 'StockArticle#update',
|
||||
stock_article_id: <%= @stock_article.id %>
|
||||
});
|
||||
|
||||
$('#modalContainer').modal('hide');
|
|
@ -36,7 +36,7 @@ de:
|
|||
created_on: Datum
|
||||
note: Notiz
|
||||
ordergroup: Bestellgruppe
|
||||
user:
|
||||
user: Eingetragen von
|
||||
group_order:
|
||||
price: Bestellsumme
|
||||
updated_by: Zuletzt bestellt
|
||||
|
@ -71,10 +71,10 @@ de:
|
|||
name: Lieferant
|
||||
note: Notiz
|
||||
starts: Läuft vom
|
||||
status:
|
||||
status: Status
|
||||
order_article:
|
||||
missing_units: Fehlende Einheiten
|
||||
missing_units_short:
|
||||
missing_units_short: Fehlende
|
||||
units_to_order: Menge
|
||||
update_current_price: Globalen Preis aktualisieren
|
||||
order_comment:
|
||||
|
@ -127,7 +127,7 @@ de:
|
|||
done: Erledigt?
|
||||
due_date: Wann erledigen?
|
||||
duration: Dauer
|
||||
name:
|
||||
name: Aufgabe
|
||||
required_users: Anzahl
|
||||
user_list: Verantwortlichen
|
||||
workgroup: Arbeitsgruppe
|
||||
|
@ -269,7 +269,7 @@ de:
|
|||
application:
|
||||
controller:
|
||||
error_authn: Anmeldung erforderlich!
|
||||
error_denied:
|
||||
error_denied: Kein Zugriff!
|
||||
error_members_only: Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!
|
||||
article_categories:
|
||||
create:
|
||||
|
@ -385,13 +385,12 @@ de:
|
|||
how_many_units: Wie viele Einheiten (%{unit}) des Artikels »%{name}« liefern?
|
||||
create:
|
||||
notice: Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen!
|
||||
create_stock_article:
|
||||
notice: Neuer Lagerartikel »%{name}« gespeichert.
|
||||
destroy:
|
||||
notice: Lieferung wurde gelöscht.
|
||||
edit:
|
||||
title: Lieferung bearbeiten
|
||||
form:
|
||||
confirm_foreign_supplier_reedit: Der Lagerartikel »%{name}« wurde erfolgreich gespeichert. Er gehört jedoch nicht zu dem Lieferanten dieser Lieferung. Möchtest Du diesen Lagerartikel erneut bearbeiten?
|
||||
create_from_blank: Ohne Vorlage anlegen
|
||||
create_stock_article: Lagerartikel anlegen
|
||||
title_fill_quantities: 2. Liefermenge angeben
|
||||
|
@ -416,15 +415,11 @@ de:
|
|||
action_add_to_delivery: Liefern
|
||||
action_edit: Bearbeiten
|
||||
action_other_price: Kopieren
|
||||
stock_article_form:
|
||||
copy_stock_article: Lagerartikel kopieren
|
||||
stock_change_fields:
|
||||
remove_article: Artikel aus Lieferung entfernen
|
||||
suppliers_overview: Lieferantenübersicht
|
||||
update:
|
||||
notice: Lieferung wurde aktualisiert.
|
||||
update_stock_article:
|
||||
notice: Lagerartikel »%{name}« aktualisiert.
|
||||
documents:
|
||||
order_by_articles:
|
||||
filename: Bestellung %{name}-%{date} - Artikelsortierung
|
||||
|
@ -708,7 +703,7 @@ de:
|
|||
ordered: Bestellt
|
||||
ordered_title: Menge + Toleranz
|
||||
show_hide: Zeige/Verstecke nicht bestellte Artikel
|
||||
show_note:
|
||||
show_note: Notiz zeigen
|
||||
title: Artikelübersicht
|
||||
unit_price: Einzelpreis
|
||||
comment: Kommentare lesen/schreiben
|
||||
|
@ -1243,9 +1238,9 @@ de:
|
|||
shared:
|
||||
articles:
|
||||
ordered: Bestellt
|
||||
ordered_desc:
|
||||
ordered_desc: Anzahl der Artikel die durch das Mitglied bestellt wurden (Menge + Toleranz)
|
||||
received: Bekommen
|
||||
received_desc:
|
||||
received_desc: Anzahl der Artikel die ein Mitglied erhält
|
||||
articles_by_articles:
|
||||
ordergroup: Bestellgruppe
|
||||
price: Gesamtpreis
|
||||
|
@ -1287,7 +1282,7 @@ de:
|
|||
units_to_order: Wenn Du die Gesamtanzahl gelieferter Gebinde änderst, musst Du auch die individuelle Anzahl der einzelnen Bestellgruppen anpassen, indem Du auf den Artikelnamen klickst. Sie werden nicht automatisch neuberechnet und andernfalls werden den Bestellgruppen Artikel in Rechnung gestellt, die nicht geliefert wurden!
|
||||
update_current_price: Ändert auch den Preis für aktuelle Bestellungen
|
||||
stock_article:
|
||||
copy_stock_article:
|
||||
copy:
|
||||
name: Bitte ändern
|
||||
edit_stock_article:
|
||||
price: <ul><li>Preisänderung gesperrt.</li><li>Bei Bedarf %{stock_article_copy_link}.</li></ul>
|
||||
|
@ -1361,11 +1356,16 @@ de:
|
|||
stockit:
|
||||
check:
|
||||
not_empty: ! '%{name} kann nicht gelöscht werden. Der Lagerbestand ist nicht null.'
|
||||
copy:
|
||||
title: Lagerartikel kopieren
|
||||
create:
|
||||
notice: Neuer Lagerartikel »%{name}« gespeichert.
|
||||
destroy:
|
||||
notice: Artikel %{name} gelöscht.
|
||||
edit:
|
||||
title: Lagerartikel bearbeiten
|
||||
form:
|
||||
copy_stock_article: Lagerartikel kopieren
|
||||
price_hint: Um Chaos zu vermeiden können bis auf weiteres die Preise von angelegten Lagerartikeln nicht mehr verändert werden.
|
||||
index:
|
||||
confirm_delete: Bist Du sicher?
|
||||
|
@ -1388,10 +1388,8 @@ de:
|
|||
new_quantity: Neuer Bestand
|
||||
reason: Ereignis
|
||||
stock_changes: Verlauf des Lagerbestands
|
||||
stock_create:
|
||||
notice: Lagerartikel wurde gespeichert.
|
||||
stock_update:
|
||||
notice: Lagerartikel wurde gespeichert.
|
||||
update:
|
||||
notice: Lagerartikel »%{name}« aktualisiert.
|
||||
suppliers:
|
||||
create:
|
||||
notice: Lieferant wurde erstellt
|
||||
|
|
|
@ -387,13 +387,12 @@ en:
|
|||
how_many_units: ! 'How many units (%{unit}) to deliver? Stock article name: %{name}.'
|
||||
create:
|
||||
notice: Delivery was created. Please don’t forget to create invoice!
|
||||
create_stock_article:
|
||||
notice: The new stock article "%{name}" was saved.
|
||||
destroy:
|
||||
notice: Delivery was deleted.
|
||||
edit:
|
||||
title: Edit delivery
|
||||
form:
|
||||
confirm_foreign_supplier_reedit: The stock article %{name} was successfully saved. However, it belongs to a different supplier than this delivery. Would you like to edit the stock article again?
|
||||
create_from_blank: Create new article
|
||||
create_stock_article: Create stock article
|
||||
title_fill_quantities: 2. Set delivery quantities
|
||||
|
@ -418,15 +417,11 @@ en:
|
|||
action_add_to_delivery: Add to delivery
|
||||
action_edit: Edit
|
||||
action_other_price: Copy
|
||||
stock_article_form:
|
||||
copy_stock_article: Copy stock article
|
||||
stock_change_fields:
|
||||
remove_article: Remove article from delivery
|
||||
suppliers_overview: Supplier overview
|
||||
update:
|
||||
notice: Delivery was updated.
|
||||
update_stock_article:
|
||||
notice: The stock article "%{name}" was updated.
|
||||
documents:
|
||||
order_by_articles:
|
||||
filename: Order %{name}-%{date} - by articles
|
||||
|
@ -1284,14 +1279,14 @@ en:
|
|||
default_message: Errors were found. Please check the form.
|
||||
hints:
|
||||
article:
|
||||
unit: ! 'For example: KG or 1L or 500g'
|
||||
unit: e.g. KG or 1L or 500g
|
||||
message:
|
||||
private: Message doesn’t show in Foodsoft mail inbox
|
||||
order_article:
|
||||
units_to_order: If you change the total amount of delivered units, you also have to change individual group amounts by clicking on the article name. They will not be automatically recalculated and so ordergroups may be accounted for articles that were not delivered!
|
||||
update_current_price: Also update the price of the current order
|
||||
stock_article:
|
||||
copy_stock_article:
|
||||
copy:
|
||||
name: Please modify
|
||||
edit_stock_article:
|
||||
price: <ul><li>Price changes are forbidden.</li><li>If necessary, %{stock_article_copy_link}.</li></ul>
|
||||
|
@ -1365,11 +1360,16 @@ en:
|
|||
stockit:
|
||||
check:
|
||||
not_empty: ! '%{name} could not be deleted, the inventory is not zero.'
|
||||
copy:
|
||||
title: Copy stock article
|
||||
create:
|
||||
notice: New stock article %{name} was created.
|
||||
destroy:
|
||||
notice: Article %{name} was deleted.
|
||||
edit:
|
||||
title: Edit stock articles
|
||||
form:
|
||||
copy_stock_article: copy stock article
|
||||
price_hint: To avoid choas, it is not possible to edit the prices of already added stock articles until further notice.
|
||||
index:
|
||||
confirm_delete: Are you sure you want to delete?
|
||||
|
@ -1392,10 +1392,10 @@ en:
|
|||
new_quantity: New quantity
|
||||
reason: Reason
|
||||
stock_changes: Stock quantity changes
|
||||
stock_create:
|
||||
notice: Stock article was created.
|
||||
stock_update:
|
||||
notice: Stock article was saved.
|
||||
stock_article:
|
||||
confirm_delete: Are you sure you want to delete the stock article %{name}?
|
||||
update:
|
||||
notice: Stock article %{name} was saved.
|
||||
suppliers:
|
||||
create:
|
||||
notice: Supplier was created
|
||||
|
|
|
@ -391,8 +391,6 @@ fr:
|
|||
how_many_units: Combien d unités (%{unit}) de l article %{name} doivent-elles être livrées?
|
||||
create:
|
||||
notice: Le réapprovisionnement a bien a été défini. Attention à ne pas oublier de déposer la facture correspondante!
|
||||
create_stock_article:
|
||||
notice: L'article "%{name}" a été ajouté au stock.
|
||||
destroy:
|
||||
notice: Le réapprovisionnement a été annulé.
|
||||
edit:
|
||||
|
@ -422,15 +420,11 @@ fr:
|
|||
action_add_to_delivery: Commander
|
||||
action_edit: Modifier
|
||||
action_other_price: Copier
|
||||
stock_article_form:
|
||||
copy_stock_article: Copier l'article
|
||||
stock_change_fields:
|
||||
remove_article: Retirer l'article de cette commande
|
||||
suppliers_overview: Liste des fournisseusEs_rs
|
||||
update:
|
||||
notice: La commande a été actualisée
|
||||
update_stock_article:
|
||||
notice: Les données de l'article "%{name}" ont été mises à jour.
|
||||
documents:
|
||||
order_by_articles:
|
||||
filename: Commande %{name}-%{date} - Trier par
|
||||
|
@ -1294,7 +1288,7 @@ fr:
|
|||
units_to_order:
|
||||
update_current_price: Modifie aussi le prix des commandes en cours
|
||||
stock_article:
|
||||
copy_stock_article:
|
||||
copy:
|
||||
name: Merci de modifier
|
||||
edit_stock_article:
|
||||
price: <ul><li>Modification du prix enregistrée. </li><li>Si nécessaire %{stock_article_copy_link}.</li></ul>
|
||||
|
@ -1370,11 +1364,16 @@ fr:
|
|||
stockit:
|
||||
check:
|
||||
not_empty: ! '%{name} ne peut pas être supprimé, car il y en a encore en stock.'
|
||||
copy:
|
||||
title:
|
||||
create:
|
||||
notice: L'article "%{name}" a été ajouté au stock.
|
||||
destroy:
|
||||
notice: L'article %{name} a bien été supprimé du stock.
|
||||
edit:
|
||||
title: Modifier l'article
|
||||
form:
|
||||
copy_stock_article: Copier l'article
|
||||
price_hint: Pour éviter que ça soit le bazar, les prix des articles en stock ne peuvent plus être modifiés.
|
||||
index:
|
||||
confirm_delete: T'es sûrE de ton coup?
|
||||
|
@ -1397,10 +1396,8 @@ fr:
|
|||
new_quantity: Nouveau stock
|
||||
reason: Raison
|
||||
stock_changes: Afficher l'historique
|
||||
stock_create:
|
||||
notice: L'article a été sauvegardé.
|
||||
stock_update:
|
||||
notice: L'article a été sauvegardé.
|
||||
update:
|
||||
notice: Les données de l'article "%{name}" ont été mises à jour.
|
||||
suppliers:
|
||||
create:
|
||||
notice: FournisseusE_r misE à jour
|
||||
|
|
|
@ -387,8 +387,6 @@ nl:
|
|||
how_many_units: ! 'Hoeveel eenheden (%{unit}) leveren? Voorraadartikel: %{name}.'
|
||||
create:
|
||||
notice: Levering is aangemaakt. Vergeet niet een factuur te maken!
|
||||
create_stock_article:
|
||||
notice: Nieuw voorraadsartikel "%{name}" gemaakt.
|
||||
destroy:
|
||||
notice: Levering is verwijdered.
|
||||
edit:
|
||||
|
@ -418,15 +416,11 @@ nl:
|
|||
action_add_to_delivery: Voeg toe aan levering
|
||||
action_edit: Bewerk
|
||||
action_other_price: Kopieer
|
||||
stock_article_form:
|
||||
copy_stock_article: kopieer het voorraadartikel
|
||||
stock_change_fields:
|
||||
remove_article: Artikel uit levering halen
|
||||
suppliers_overview: Leverancieroverzicht
|
||||
update:
|
||||
notice: Levering is bijgewerkt.
|
||||
update_stock_article:
|
||||
notice: Voorraadartikel "%{name}" is bijgewerkt.
|
||||
documents:
|
||||
order_by_articles:
|
||||
filename: Bestelling %{name}-%{date} - Artikellijst
|
||||
|
@ -1271,7 +1265,7 @@ nl:
|
|||
units_to_order: Als je het aantal geleverde eenheden wijzigt, moet je daarna de hoeveelheden voor huishoudens aanpassen. Klik daarvoor op de artikelnaam. Als je dit vergeet, kunnen huishoudens belast worden voor artikelen die ze niet hebben gekregen!
|
||||
update_current_price: Ook prijs in huidige besteling aanpassen
|
||||
stock_article:
|
||||
copy_stock_article:
|
||||
copy:
|
||||
name: Wijzigen alsjeblieft
|
||||
edit_stock_article:
|
||||
price: <ul><li>De prijs mag niet aangepast worden.</li><li>Indien nodig, %{stock_article_copy_link}.</li></ul>
|
||||
|
@ -1345,11 +1339,16 @@ nl:
|
|||
stockit:
|
||||
check:
|
||||
not_empty: ! '%{name} kon niet worden verwijderd, de inventaris is niet leeg.'
|
||||
copy:
|
||||
title:
|
||||
create:
|
||||
notice: Nieuw voorraadsartikel "%{name}" gemaakt.
|
||||
destroy:
|
||||
notice: Artikel %{name} is verwijdered.
|
||||
edit:
|
||||
title: Voorraadartikelen bewerken
|
||||
form:
|
||||
copy_stock_article: kopieer het voorraadartikel
|
||||
price_hint: Om chaos te voorkomen, kun je de prijs van bestaande voorraadartikelen niet aanpassen.
|
||||
index:
|
||||
confirm_delete: Weet je zeker dat je dit wilt verwijderen?
|
||||
|
@ -1372,10 +1371,8 @@ nl:
|
|||
new_quantity: Nieuw aantal
|
||||
reason: Reden
|
||||
stock_changes: Verloop
|
||||
stock_create:
|
||||
notice: Voorraadsartikel is opgeslagen.
|
||||
stock_update:
|
||||
notice: Voorraadsartikel is bijgewerkt.
|
||||
update:
|
||||
notice: Voorraadartikel "%{name}" is bijgewerkt.
|
||||
suppliers:
|
||||
create:
|
||||
notice: Leverancier is aangemaakt.
|
||||
|
|
|
@ -86,9 +86,14 @@ Foodsoft::Application.routes.draw do
|
|||
end
|
||||
|
||||
resources :stock_articles, :to => 'stockit' do
|
||||
get :copy
|
||||
collection do
|
||||
get :articles_search
|
||||
get :fill_new_stock_article_form
|
||||
get :derive
|
||||
|
||||
get :index_on_stock_article_create
|
||||
get :index_on_stock_article_update
|
||||
|
||||
get :show_on_stock_article_update
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -96,15 +101,12 @@ Foodsoft::Application.routes.draw do
|
|||
get :shared_suppliers, :on => :collection
|
||||
|
||||
resources :deliveries do
|
||||
post :add_stock_change, :on => :collection
|
||||
|
||||
get :new_stock_article, :on => :collection
|
||||
get :copy_stock_article, :on => :collection
|
||||
get :derive_stock_article, :on => :collection
|
||||
post :create_stock_article, :on => :collection
|
||||
|
||||
get :edit_stock_article, :on => :collection
|
||||
put :update_stock_article, :on => :collection
|
||||
collection do
|
||||
post :add_stock_change
|
||||
|
||||
get :form_on_stock_article_create
|
||||
get :form_on_stock_article_update
|
||||
end
|
||||
end
|
||||
|
||||
resources :articles do
|
||||
|
|
|
@ -17,6 +17,9 @@ Getting started
|
|||
```
|
||||
git clone https://github.com/foodcoops/foodsoft.git
|
||||
```
|
||||
This brings up the bleeding-edge development version, which might contain some
|
||||
unfinished parts. If you want to be safe, choose the last release:
|
||||
`git checkout $(git tag -l | grep ^v | sort -rn | head -n1)`
|
||||
|
||||
1. Install RVM and Ruby 1.9.3 (if you have not done so before):
|
||||
```
|
||||
|
|
40
doc/design_patterns/publish_subscribe.md
Normal file
40
doc/design_patterns/publish_subscribe.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Publish/subscribe pattern
|
||||
## Handling DOM updates after AJAX database manipulation
|
||||
|
||||
As an example, let us consider the manipulation (create, update...) of `StockArticles`. This can be done in different views, e.g., `stock_articles/index`, `stock_articles/show` and `deliveries/_form` through modals using AJAX requests. As an advantage of the AJAX technique, the user does not need to reload the entire page. However, (after the update of the `StockArticle` in the database) it is generally required to update the DOM in the current view such that the page properly reacts to the asynchronous actions.
|
||||
|
||||
The process can be divided in two steps: **1.** AJAX database manipulation and **2.** DOM updates for the particular view. The crucial point is the coupling of the two steps since the controller for the first step offers the same functionality to all views and does not need to know anything about the current view.
|
||||
|
||||
### 1. AJAX database manipulation
|
||||
**(i)** Example: current view `deliveries/_form` offers a link for the AJAX action `StockArticle#new`. This opens a modal filled with `stock_articles/_form`.
|
||||
|
||||
**(ii)** AJAX form post addresses the `StockArticle#create` action which handles the database manipulation.
|
||||
|
||||
**(iii)** The database manipulation is finished by the rendering of, e.g., `stock_articles/create.js.erb`. The key task there is to **publish** the database changes by calling `trigger`, i.e.,
|
||||
|
||||
$(document).trigger({
|
||||
type: 'StockArticle#create',
|
||||
stock_article_id: <%= @stock_article.id %>
|
||||
});
|
||||
|
||||
### 2. DOM updates for the particular view
|
||||
**(i)** Each view has the opportunity to **subscribe** to particular events of the previous step. A very simple example is the update of the `stock_articles/index` view after `StockArticle#destroy`:
|
||||
|
||||
$(document).on('StockArticle#destroy', function(e) {
|
||||
$('#stockArticle-' + e.stock_article_id).remove();
|
||||
});
|
||||
|
||||
However, in most of the situations you will like to use the full power of the MVC framework in order to read new data from the database and render some partial. Let us consider this slightly more advanced case in the following.
|
||||
|
||||
The view `stock_articles/index` could listen (amongst others) to `StockArticle#create` like this:
|
||||
|
||||
$(document).on('StockArticle#create', function(e) {
|
||||
$.ajax({
|
||||
url: '#{index_on_stock_article_create_stock_articles_path}',
|
||||
type: 'get',
|
||||
data: {id: e.stock_article_id},
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
});
|
||||
});
|
||||
|
||||
**(ii)** The action `StockArticles#index_on_stock_article_create` is a special helper action to handle DOM updates of the `stock_articles/index` view after the creation of a new `StockArticle` with the given `id`.
|
|
@ -1,14 +1,26 @@
|
|||
# optional test coverage
|
||||
# needs to be loaded first, e.g. add a require at top of spec_helper
|
||||
if ENV['COVERAGE']
|
||||
if ENV['COVERAGE'] or ENV['COVERALLS']
|
||||
require 'simplecov'
|
||||
|
||||
# update coveralls.io on Travis CI
|
||||
if ENV['COVERALLS']
|
||||
require 'coveralls'
|
||||
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
||||
end
|
||||
|
||||
# slightly tweaked coverage reporting
|
||||
def cov_no_plugins(source_file, path)
|
||||
source_file.filename =~ /#{path}/ and not source_file.filename =~ /\/lib\/foodsoft_.*\//
|
||||
end
|
||||
SimpleCov.start do
|
||||
add_filter '/spec/'
|
||||
add_filter '/test/'
|
||||
add_group 'Models', '/app/models/'
|
||||
add_group 'Controllers', '/app/controllers/'
|
||||
add_group 'Helpers', '/app/helpers/'
|
||||
add_group 'Documents', '/app/documents/'
|
||||
add_group 'Libraries', '/lib/'
|
||||
add_group 'Models' do |s| cov_no_plugins s, '/app/models/' end
|
||||
add_group 'Controllers' do |s| cov_no_plugins s, '/app/controllers/' end
|
||||
add_group 'Helpers' do |s| cov_no_plugins s, '/app/helpers/' end
|
||||
add_group 'Documents' do |s| cov_no_plugins s, '/app/documents/' end
|
||||
add_group 'Libraries' do |s| cov_no_plugins s, '/lib/' end
|
||||
add_group 'Plugins' do |s| s.filename =~ /\/lib\/foodsoft_.*\// end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue