From e99752e483537a81f7cedad8b547588a96ae37a3 Mon Sep 17 00:00:00 2001 From: Julius Rapp Date: Fri, 6 Dec 2013 18:33:35 +0100 Subject: [PATCH 01/14] disable escape of html from local (one place) --- app/views/deliveries/_stock_article_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/deliveries/_stock_article_form.html.haml b/app/views/deliveries/_stock_article_form.html.haml index 21c5b216..5fdce8de 100644 --- a/app/views/deliveries/_stock_article_form.html.haml +++ b/app/views/deliveries/_stock_article_form.html.haml @@ -16,7 +16,7 @@ %span.add-on % = f.input :deposit - else - = f.input :price, :input_html => {:disabled => 'disabled'}, :hint => stock_article_price_hint(stock_article) + = 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'} From dd08e277c7d4af7be05399c84c906954e327ea4e Mon Sep 17 00:00:00 2001 From: Julius Rapp Date: Sat, 7 Dec 2013 11:20:03 +0100 Subject: [PATCH 02/14] AJAX_ify StockArticle manipulation; Introduce publish/subscribe pattern for DOM updates --- app/controllers/stockit_controller.rb | 54 ++++++++++++++++--- app/helpers/stockit_helper.rb | 9 ++++ app/views/stockit/_form.html.haml | 39 +++++++------- app/views/stockit/_stock_article.html.haml | 14 +++++ .../stockit/_stock_article_details.html.haml | 26 +++++++++ app/views/stockit/copy.js.erb | 9 ++++ app/views/stockit/create.js.erb | 15 ++++++ app/views/stockit/destroy.js.erb | 13 +++++ app/views/stockit/destroy.js.haml | 8 --- app/views/stockit/edit.html.haml | 3 -- app/views/stockit/edit.js.erb | 9 ++++ app/views/stockit/index.html.haml | 45 ++++++++++------ .../index_on_stock_article_create.js.erb | 12 +++++ .../index_on_stock_article_update.js.erb | 12 +++++ app/views/stockit/new.html.haml | 22 -------- app/views/stockit/new.js.erb | 9 ++++ app/views/stockit/show.html.haml | 40 ++++++-------- .../show_on_stock_article_update.js.erb | 13 +++++ app/views/stockit/update.js.erb | 15 ++++++ config/locales/en.yml | 14 ++--- config/routes.rb | 6 +++ doc/design_patterns/publish_subscribe.md | 33 ++++++++++++ 22 files changed, 313 insertions(+), 107 deletions(-) create mode 100644 app/views/stockit/_stock_article.html.haml create mode 100644 app/views/stockit/_stock_article_details.html.haml create mode 100644 app/views/stockit/copy.js.erb create mode 100644 app/views/stockit/create.js.erb create mode 100644 app/views/stockit/destroy.js.erb delete mode 100644 app/views/stockit/destroy.js.haml delete mode 100644 app/views/stockit/edit.html.haml create mode 100644 app/views/stockit/edit.js.erb create mode 100644 app/views/stockit/index_on_stock_article_create.js.erb create mode 100644 app/views/stockit/index_on_stock_article_update.js.erb delete mode 100644 app/views/stockit/new.html.haml create mode 100644 app/views/stockit/new.js.erb create mode 100644 app/views/stockit/show_on_stock_article_update.js.erb create mode 100644 app/views/stockit/update.js.erb create mode 100644 doc/design_patterns/publish_subscribe.md diff --git a/app/controllers/stockit_controller.rb b/app/controllers/stockit_controller.rb index 475ac3a3..85c027ea 100644 --- a/app/controllers/stockit_controller.rb +++ b/app/controllers/stockit_controller.rb @@ -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, diff --git a/app/helpers/stockit_helper.rb b/app/helpers/stockit_helper.rb index f6a0a1fc..aee6708e 100644 --- a/app/helpers/stockit_helper.rb +++ b/app/helpers/stockit_helper.rb @@ -14,4 +14,13 @@ module StockitHelper link_to t('.stock_taking'), 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 diff --git a/app/views/stockit/_form.html.haml b/app/views/stockit/_form.html.haml index 32e58623..1e56b2c2 100644 --- a/app/views/stockit/_form.html.haml +++ b/app/views/stockit/_form.html.haml @@ -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') diff --git a/app/views/stockit/_stock_article.html.haml b/app/views/stockit/_stock_article.html.haml new file mode 100644 index 00000000..c2eb3566 --- /dev/null +++ b/app/views/stockit/_stock_article.html.haml @@ -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 - stock_article.quantity_available + %th= 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 diff --git a/app/views/stockit/_stock_article_details.html.haml b/app/views/stockit/_stock_article_details.html.haml new file mode 100644 index 00000000..617799e7 --- /dev/null +++ b/app/views/stockit/_stock_article_details.html.haml @@ -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' diff --git a/app/views/stockit/copy.js.erb b/app/views/stockit/copy.js.erb new file mode 100644 index 00000000..e3bc3321 --- /dev/null +++ b/app/views/stockit/copy.js.erb @@ -0,0 +1,9 @@ +$('#modalContainer').html('<%= j(render( + :partial => "form", + :locals => { + :title => t('.title'), + :stock_article => @stock_article + } +)) %>'); + +$('#modalContainer').modal(); diff --git a/app/views/stockit/create.js.erb b/app/views/stockit/create.js.erb new file mode 100644 index 00000000..aa75b2dc --- /dev/null +++ b/app/views/stockit/create.js.erb @@ -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'); diff --git a/app/views/stockit/destroy.js.erb b/app/views/stockit/destroy.js.erb new file mode 100644 index 00000000..7bba9dbf --- /dev/null +++ b/app/views/stockit/destroy.js.erb @@ -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 %> +}); diff --git a/app/views/stockit/destroy.js.haml b/app/views/stockit/destroy.js.haml deleted file mode 100644 index 8bbde9ed..00000000 --- a/app/views/stockit/destroy.js.haml +++ /dev/null @@ -1,8 +0,0 @@ --# please polish the following line if you know how, same in partial _destroy_fail -var successDiv = $(''); - -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. diff --git a/app/views/stockit/edit.html.haml b/app/views/stockit/edit.html.haml deleted file mode 100644 index bdf498c6..00000000 --- a/app/views/stockit/edit.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- title t('.title') - -= render :partial => 'form', :locals => {:stock_article => @stock_article} diff --git a/app/views/stockit/edit.js.erb b/app/views/stockit/edit.js.erb new file mode 100644 index 00000000..e3bc3321 --- /dev/null +++ b/app/views/stockit/edit.js.erb @@ -0,0 +1,9 @@ +$('#modalContainer').html('<%= j(render( + :partial => "form", + :locals => { + :title => t('.title'), + :stock_article => @stock_article + } +)) %>'); + +$('#modalContainer').modal(); diff --git a/app/views/stockit/index.html.haml b/app/views/stockit/index.html.haml index c2899d9e..0fbd2722 100644 --- a/app/views/stockit/index.html.haml +++ b/app/views/stockit/index.html.haml @@ -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= t '.article.supplier' %th= t '.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 - article.quantity_available - %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 diff --git a/app/views/stockit/index_on_stock_article_create.js.erb b/app/views/stockit/index_on_stock_article_create.js.erb new file mode 100644 index 00000000..eb48001b --- /dev/null +++ b/app/views/stockit/index_on_stock_article_create.js.erb @@ -0,0 +1,12 @@ +// Handle more advanced DOM update after AJAX database manipulation. +// See publish/subscribe design pattern in /doc. +(function() { + var stock_article_row = $('<%= j(render( + :partial => 'stock_article', + :locals => { + :stock_article => @stock_article + } + )) %>'); + + $('#articles-tbody').prepend(stock_article_row); +})(); diff --git a/app/views/stockit/index_on_stock_article_update.js.erb b/app/views/stockit/index_on_stock_article_update.js.erb new file mode 100644 index 00000000..6e43db8e --- /dev/null +++ b/app/views/stockit/index_on_stock_article_update.js.erb @@ -0,0 +1,12 @@ +// Handle more advanced DOM update after AJAX database manipulation. +// See publish/subscribe design pattern in /doc. +(function() { + var stock_article_row = $('<%= j(render( + :partial => 'stock_article', + :locals => { + :stock_article => @stock_article + } + )) %>'); + + $('#stockArticle-<%= @stock_article.id %>').replaceWith(stock_article_row); +})(); diff --git a/app/views/stockit/new.html.haml b/app/views/stockit/new.html.haml deleted file mode 100644 index 05609a84..00000000 --- a/app/views/stockit/new.html.haml +++ /dev/null @@ -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} diff --git a/app/views/stockit/new.js.erb b/app/views/stockit/new.js.erb new file mode 100644 index 00000000..e3bc3321 --- /dev/null +++ b/app/views/stockit/new.js.erb @@ -0,0 +1,9 @@ +$('#modalContainer').html('<%= j(render( + :partial => "form", + :locals => { + :title => t('.title'), + :stock_article => @stock_article + } +)) %>'); + +$('#modalContainer').modal(); diff --git a/app/views/stockit/show.html.haml b/app/views/stockit/show.html.haml index 5f416bf9..077b6e3a 100644 --- a/app/views/stockit/show.html.haml +++ b/app/views/stockit/show.html.haml @@ -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') diff --git a/app/views/stockit/show_on_stock_article_update.js.erb b/app/views/stockit/show_on_stock_article_update.js.erb new file mode 100644 index 00000000..ce057f89 --- /dev/null +++ b/app/views/stockit/show_on_stock_article_update.js.erb @@ -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) %>'); +})(); diff --git a/app/views/stockit/update.js.erb b/app/views/stockit/update.js.erb new file mode 100644 index 00000000..830d846c --- /dev/null +++ b/app/views/stockit/update.js.erb @@ -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'); diff --git a/config/locales/en.yml b/config/locales/en.yml index a48acd92..7011146f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1348,7 +1348,7 @@ en: 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: @@ -1421,8 +1421,10 @@ en: stockit: check: not_empty: ! '%{name} could not be deleted, the inventory is not zero.' + create: + notice: New stock article »%{name}« was created. destroy: - notice: Article %{name} was deleted. + notice: Article »%{name}« was deleted. edit: title: Edit stock articles form: @@ -1461,10 +1463,10 @@ en: reason: Reason stock_changes: Stock quantity changes stock_taking: Inventory - 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 diff --git a/config/routes.rb b/config/routes.rb index 655a1038..62678230 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -86,9 +86,15 @@ 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 :index_on_stock_article_create + get :index_on_stock_article_update + + get :show_on_stock_article_update end end diff --git a/doc/design_patterns/publish_subscribe.md b/doc/design_patterns/publish_subscribe.md new file mode 100644 index 00000000..d261d45a --- /dev/null +++ b/doc/design_patterns/publish_subscribe.md @@ -0,0 +1,33 @@ +# 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 + 1. Example: current view `deliveries/_form` offers a link for the AJAX action `StockArticle#new`. This opens a modal filled with `stock_articles/_form`. + 2. AJAX form post addresses the `StockArticle#create` action which handles the database manipulation. + 3. 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 + 1. 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' + }); + }); + 2. 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`. From 13bb4e0a8be6fa708ab954ff8f95b1b715156250 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 15:12:08 +0100 Subject: [PATCH 03/14] Rename 'simple_form.hints.stock_article.copy_stock_article' to 'simple_form.hints.stock_article.copy' --- config/locales/de.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/nl.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 67285827..d2ca5be0 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1346,7 +1346,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:
  • Preisänderung gesperrt.
  • Bei Bedarf %{stock_article_copy_link}.
diff --git a/config/locales/fr.yml b/config/locales/fr.yml index bf07f516..5b947f08 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1353,7 +1353,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:
  • Modification du prix enregistrée.
  • Si nécessaire %{stock_article_copy_link}.
diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 9f34742f..f907d54c 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1330,7 +1330,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:
  • De prijs mag niet aangepast worden.
  • Indien nodig, %{stock_article_copy_link}.
From bceabfec5c552917f70f1dffaca41d34296d6e04 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 16:42:25 +0100 Subject: [PATCH 04/14] Apply publish/subscribe pattern to stock_article manipulation in delivery form --- app/controllers/deliveries_controller.rb | 59 ++++--------------- app/helpers/deliveries_helper.rb | 9 --- app/views/deliveries/_form.html.haml | 26 +++++++- .../_stock_article_for_adding.html.haml | 4 +- .../deliveries/_stock_article_form.html.haml | 23 -------- .../deliveries/copy_stock_article.js.erb | 5 -- .../deliveries/derive_stock_article.js.erb | 5 -- .../deliveries/edit_stock_article.js.erb | 5 -- ...rb => form_on_stock_article_create.js.erb} | 8 +-- ...rb => form_on_stock_article_update.js.erb} | 8 +-- app/views/deliveries/new_stock_article.js.erb | 5 -- app/views/stockit/derive.js.erb | 9 +++ config/routes.rb | 18 +++--- 13 files changed, 57 insertions(+), 127 deletions(-) delete mode 100644 app/views/deliveries/_stock_article_form.html.haml delete mode 100644 app/views/deliveries/copy_stock_article.js.erb delete mode 100644 app/views/deliveries/derive_stock_article.js.erb delete mode 100644 app/views/deliveries/edit_stock_article.js.erb rename app/views/deliveries/{create_stock_article.js.erb => form_on_stock_article_create.js.erb} (64%) rename app/views/deliveries/{update_stock_article.js.erb => form_on_stock_article_update.js.erb} (81%) delete mode 100644 app/views/deliveries/new_stock_article.js.erb create mode 100644 app/views/stockit/derive.js.erb diff --git a/app/controllers/deliveries_controller.rb b/app/controllers/deliveries_controller.rb index 86eedc14..3f18899f 100644 --- a/app/controllers/deliveries_controller.rb +++ b/app/controllers/deliveries_controller.rb @@ -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 diff --git a/app/helpers/deliveries_helper.rb b/app/helpers/deliveries_helper.rb index b23107cc..2ef5d14b 100644 --- a/app/helpers/deliveries_helper.rb +++ b/app/helpers/deliveries_helper.rb @@ -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 diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml index 3e1a3b6c..533f44c3 100644 --- a/app/views/deliveries/_form.html.haml +++ b/app/views/deliveries/_form.html.haml @@ -42,7 +42,7 @@ } 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}}, contentType: 'application/json; charset=UTF-8' @@ -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 diff --git a/app/views/deliveries/_stock_article_for_adding.html.haml b/app/views/deliveries/_stock_article_for_adding.html.haml index b43df782..956d8379 100644 --- a/app/views/deliveries/_stock_article_for_adding.html.haml +++ b/app/views/deliveries/_stock_article_for_adding.html.haml @@ -5,7 +5,7 @@ %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' + = 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' - deliver_button_disabled = ( @delivery and @delivery.includes_article? article ) ? ( 'disabled' ) : ( false ) = 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 diff --git a/app/views/deliveries/_stock_article_form.html.haml b/app/views/deliveries/_stock_article_form.html.haml deleted file mode 100644 index 5fdce8de..00000000 --- a/app/views/deliveries/_stock_article_form.html.haml +++ /dev/null @@ -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') diff --git a/app/views/deliveries/copy_stock_article.js.erb b/app/views/deliveries/copy_stock_article.js.erb deleted file mode 100644 index de5d260e..00000000 --- a/app/views/deliveries/copy_stock_article.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -$('#modalContainer').html( - '<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>' -); - -$('#modalContainer').modal(); diff --git a/app/views/deliveries/derive_stock_article.js.erb b/app/views/deliveries/derive_stock_article.js.erb deleted file mode 100644 index de5d260e..00000000 --- a/app/views/deliveries/derive_stock_article.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -$('#modalContainer').html( - '<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>' -); - -$('#modalContainer').modal(); diff --git a/app/views/deliveries/edit_stock_article.js.erb b/app/views/deliveries/edit_stock_article.js.erb deleted file mode 100644 index de5d260e..00000000 --- a/app/views/deliveries/edit_stock_article.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -$('#modalContainer').html( - '<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>' -); - -$('#modalContainer').modal(); diff --git a/app/views/deliveries/create_stock_article.js.erb b/app/views/deliveries/form_on_stock_article_create.js.erb similarity index 64% rename from app/views/deliveries/create_stock_article.js.erb rename to app/views/deliveries/form_on_stock_article_create.js.erb index cb9d0159..25360761 100644 --- a/app/views/deliveries/create_stock_article.js.erb +++ b/app/views/deliveries/form_on_stock_article_create.js.erb @@ -1,7 +1,5 @@ -$('div.container-fluid').prepend( - '<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @stock_article.name)})) %>' -); - +// Handle more advanced DOM update after AJAX database manipulation. +// See publish/subscribe design pattern in /doc. (function() { $('#stock_articles_for_adding tr').removeClass('success'); @@ -12,5 +10,3 @@ $('div.container-fluid').prepend( $('#stock_articles_for_adding tbody').append(stock_article_for_adding); updateSort('#stock_articles_for_adding'); })(); - -$('#modalContainer').modal('hide'); diff --git a/app/views/deliveries/update_stock_article.js.erb b/app/views/deliveries/form_on_stock_article_update.js.erb similarity index 81% rename from app/views/deliveries/update_stock_article.js.erb rename to app/views/deliveries/form_on_stock_article_update.js.erb index 7b2d56d6..a993ab8d 100644 --- a/app/views/deliveries/update_stock_article.js.erb +++ b/app/views/deliveries/form_on_stock_article_update.js.erb @@ -1,7 +1,5 @@ -$('div.container-fluid').prepend( - '<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @stock_article.name)})) %>' -); - +// Handle more advanced DOM update after AJAX database manipulation. +// See publish/subscribe design pattern in /doc. (function() { // update entry in stock_article table @@ -28,5 +26,3 @@ $('div.container-fluid').prepend( updateSort('#stock_changes'); })(); - -$('#modalContainer').modal('hide'); diff --git a/app/views/deliveries/new_stock_article.js.erb b/app/views/deliveries/new_stock_article.js.erb deleted file mode 100644 index de5d260e..00000000 --- a/app/views/deliveries/new_stock_article.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -$('#modalContainer').html( - '<%= j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article})) %>' -); - -$('#modalContainer').modal(); diff --git a/app/views/stockit/derive.js.erb b/app/views/stockit/derive.js.erb new file mode 100644 index 00000000..e3bc3321 --- /dev/null +++ b/app/views/stockit/derive.js.erb @@ -0,0 +1,9 @@ +$('#modalContainer').html('<%= j(render( + :partial => "form", + :locals => { + :title => t('.title'), + :stock_article => @stock_article + } +)) %>'); + +$('#modalContainer').modal(); diff --git a/config/routes.rb b/config/routes.rb index 62678230..efb355d9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -88,8 +88,7 @@ Foodsoft::Application.routes.draw do 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 @@ -102,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 From 3e49104318737228f50e02c5ab42169933a1df2e Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 16:44:16 +0100 Subject: [PATCH 05/14] Revert wrong quotation mark in English locale --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 5912b041..989c09ae 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1425,7 +1425,7 @@ en: check: not_empty: ! '%{name} could not be deleted, the inventory is not zero.' create: - notice: New stock article »%{name}« was created. + notice: New stock article %{name} was created. destroy: notice: Article »%{name}« was deleted. edit: From 92f560e1895334e50336c5dc31dbead6084016aa Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 16:46:16 +0100 Subject: [PATCH 06/14] Again revert wrong quotation mark in English locale --- config/locales/en.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 989c09ae..286847d9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1427,7 +1427,7 @@ en: create: notice: New stock article %{name} was created. destroy: - notice: Article »%{name}« was deleted. + notice: Article %{name} was deleted. edit: title: Edit stock articles form: @@ -1454,9 +1454,9 @@ en: reason: Reason stock_changes: Stock quantity changes stock_article: - confirm_delete: Are you sure you want to delete the stock article »%{name}«? + confirm_delete: Are you sure you want to delete the stock article %{name}? update: - notice: Stock article »%{name}« was saved. + notice: Stock article %{name} was saved. suppliers: create: notice: Supplier was created From 012327dd7c588fc6395eb76e76765f422fcb386e Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 16:57:53 +0100 Subject: [PATCH 07/14] Slightly cleanup delivery form --- app/views/deliveries/_stock_article_for_adding.html.haml | 6 ++++-- app/views/deliveries/form_on_stock_article_update.js.erb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/deliveries/_stock_article_for_adding.html.haml b/app/views/deliveries/_stock_article_for_adding.html.haml index 956d8379..8575c121 100644 --- a/app/views/deliveries/_stock_article_for_adding.html.haml +++ b/app/views/deliveries/_stock_article_for_adding.html.haml @@ -1,4 +1,7 @@ -- 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 @@ -7,5 +10,4 @@ %td = 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' - - deliver_button_disabled = ( @delivery and @delivery.includes_article? article ) ? ( 'disabled' ) : ( false ) = 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 diff --git a/app/views/deliveries/form_on_stock_article_update.js.erb b/app/views/deliveries/form_on_stock_article_update.js.erb index a993ab8d..a5a90d94 100644 --- a/app/views/deliveries/form_on_stock_article_update.js.erb +++ b/app/views/deliveries/form_on_stock_article_update.js.erb @@ -6,7 +6,7 @@ $('#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})) %>' + '<%= j(render(:partial => 'stock_article_for_adding', :locals => {:article => @stock_article})) %>' ).addClass('success'); $('#stock_article_<%= @stock_article.id %>').replaceWith(stock_article_for_adding); From cdb87a838986b50c69a330ac6d87ee81007ee4b2 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:10:40 +0100 Subject: [PATCH 08/14] Highlight created/updated stock_article in StockArticle#index view --- app/assets/stylesheets/bootstrap_and_overrides.css.less | 4 ++++ app/views/stockit/_stock_article.html.haml | 2 +- app/views/stockit/index_on_stock_article_create.js.erb | 4 +++- app/views/stockit/index_on_stock_article_update.js.erb | 4 +++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less index 42fde3d5..06360aa2 100644 --- a/app/assets/stylesheets/bootstrap_and_overrides.css.less +++ b/app/assets/stylesheets/bootstrap_and_overrides.css.less @@ -104,6 +104,10 @@ table { td.odd { background-color: @tableBackgroundAccent; } + + td.main_info { + font-weight: bold; + } tr.selected td { background-color: @successBackground; diff --git a/app/views/stockit/_stock_article.html.haml b/app/views/stockit/_stock_article.html.haml index 3a76083c..72d4c510 100644 --- a/app/views/stockit/_stock_article.html.haml +++ b/app/views/stockit/_stock_article.html.haml @@ -2,7 +2,7 @@ %td= link_to stock_article.name, stock_article %td= stock_article.quantity %td= stock_article.quantity_ordered - %th= stock_article.quantity_available + %td.main_info= stock_article.quantity_available %td= stock_article.unit %td= stock_article.price %td= number_to_percentage stock_article.tax diff --git a/app/views/stockit/index_on_stock_article_create.js.erb b/app/views/stockit/index_on_stock_article_create.js.erb index eb48001b..14a3bc90 100644 --- a/app/views/stockit/index_on_stock_article_create.js.erb +++ b/app/views/stockit/index_on_stock_article_create.js.erb @@ -1,12 +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); })(); diff --git a/app/views/stockit/index_on_stock_article_update.js.erb b/app/views/stockit/index_on_stock_article_update.js.erb index 6e43db8e..f2f644ba 100644 --- a/app/views/stockit/index_on_stock_article_update.js.erb +++ b/app/views/stockit/index_on_stock_article_update.js.erb @@ -1,12 +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); })(); From 0f141cb709b83ad54eed0b4d2956b844993255e6 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:14:30 +0100 Subject: [PATCH 09/14] Try to fix markdown formating issue in publish_subscribe.md --- doc/design_patterns/publish_subscribe.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/design_patterns/publish_subscribe.md b/doc/design_patterns/publish_subscribe.md index d261d45a..6d7d9696 100644 --- a/doc/design_patterns/publish_subscribe.md +++ b/doc/design_patterns/publish_subscribe.md @@ -9,12 +9,15 @@ The process can be divided in two steps: **1.** AJAX database manipulation and * 1. Example: current view `deliveries/_form` offers a link for the AJAX action `StockArticle#new`. This opens a modal filled with `stock_articles/_form`. 2. AJAX form post addresses the `StockArticle#create` action which handles the database manipulation. 3. 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 1. 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(); }); @@ -22,6 +25,7 @@ The process can be divided in two steps: **1.** AJAX database manipulation and * 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}', @@ -30,4 +34,5 @@ The process can be divided in two steps: **1.** AJAX database manipulation and * contentType: 'application/json; charset=UTF-8' }); }); + 2. 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`. From 38cbd47a2fca53d415046b71179b43d2ab8a867f Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:27:45 +0100 Subject: [PATCH 10/14] Fix markdown formating issue in publish_subscribe.md --- doc/design_patterns/publish_subscribe.md | 34 +++++++++++++----------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/doc/design_patterns/publish_subscribe.md b/doc/design_patterns/publish_subscribe.md index 6d7d9696..7c9884ad 100644 --- a/doc/design_patterns/publish_subscribe.md +++ b/doc/design_patterns/publish_subscribe.md @@ -5,27 +5,29 @@ As an example, let us consider the manipulation (create, update...) of `StockArt 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 - 1. Example: current view `deliveries/_form` offers a link for the AJAX action `StockArticle#new`. This opens a modal filled with `stock_articles/_form`. - 2. AJAX form post addresses the `StockArticle#create` action which handles the database manipulation. - 3. 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., - +### 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 - 1. 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`: - + +### 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: - + +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}', @@ -34,5 +36,5 @@ The process can be divided in two steps: **1.** AJAX database manipulation and * contentType: 'application/json; charset=UTF-8' }); }); - - 2. 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`. + +**(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`. From 047a3f63c1d8adcd212263d6bace54812c692a06 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:29:44 +0100 Subject: [PATCH 11/14] Finally fix markdown formating issue in publish_subscribe.md --- doc/design_patterns/publish_subscribe.md | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/design_patterns/publish_subscribe.md b/doc/design_patterns/publish_subscribe.md index 7c9884ad..eef6fa1d 100644 --- a/doc/design_patterns/publish_subscribe.md +++ b/doc/design_patterns/publish_subscribe.md @@ -12,29 +12,29 @@ The process can be divided in two steps: **1.** AJAX database manipulation and * **(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 %> - }); + $(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(); - }); + $(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' - }); - }); + $(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`. From 7a673b1a8b99d6229015795a051e051dc09126d4 Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:48:04 +0100 Subject: [PATCH 12/14] Move stock_article locales from delivery to stock_article --- config/locales/de.yml | 15 +++++---------- config/locales/en.yml | 7 +------ config/locales/fr.yml | 15 +++++---------- config/locales/nl.yml | 15 +++++---------- 4 files changed, 16 insertions(+), 36 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index d2ca5be0..93a1bc7f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -405,8 +405,6 @@ 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: @@ -446,15 +444,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 @@ -1420,11 +1414,14 @@ de: stockit: check: not_empty: ! '%{name} kann nicht gelöscht werden. Der Lagerbestand ist nicht null.' + 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? @@ -1447,10 +1444,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_stock_article: + notice: Lagerartikel »%{name}« aktualisiert. suppliers: create: notice: Lieferant wurde erstellt diff --git a/config/locales/en.yml b/config/locales/en.yml index 286847d9..e95ae192 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -407,8 +407,6 @@ 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: @@ -448,15 +446,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 @@ -1431,6 +1425,7 @@ en: 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? diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 5b947f08..1a62008a 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -411,8 +411,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: @@ -452,15 +450,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 @@ -1429,11 +1423,14 @@ fr: stockit: check: not_empty: ! '%{name} ne peut pas être supprimé, car il y en a encore en stock.' + 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? @@ -1456,10 +1453,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 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index f907d54c..0d768c9d 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -407,8 +407,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: @@ -448,15 +446,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 @@ -1404,11 +1398,14 @@ nl: stockit: check: not_empty: ! '%{name} kon niet worden verwijderd, de inventaris is niet leeg.' + 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? @@ -1431,10 +1428,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. From 7eb64e3c9d8ebef7ebcb86155be66e9c1110164b Mon Sep 17 00:00:00 2001 From: Julius Date: Sat, 7 Dec 2013 17:58:06 +0100 Subject: [PATCH 13/14] Update locales --- config/locales/de.yml | 4 +++- config/locales/en.yml | 2 ++ config/locales/fr.yml | 2 ++ config/locales/nl.yml | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 93a1bc7f..2e5e11a3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1414,6 +1414,8 @@ 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: @@ -1444,7 +1446,7 @@ de: new_quantity: Neuer Bestand reason: Ereignis stock_changes: Verlauf des Lagerbestands - update_stock_article: + update: notice: Lagerartikel »%{name}« aktualisiert. suppliers: create: diff --git a/config/locales/en.yml b/config/locales/en.yml index e95ae192..9d7849f6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1418,6 +1418,8 @@ 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: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 1a62008a..17a6410b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1423,6 +1423,8 @@ 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: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 0d768c9d..a1a70c25 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1398,6 +1398,8 @@ nl: stockit: check: not_empty: ! '%{name} kon niet worden verwijderd, de inventaris is niet leeg.' + copy: + title: create: notice: Nieuw voorraadsartikel "%{name}" gemaakt. destroy: From 30b35cdd110fba80242cdea9d3b5c43f1804a462 Mon Sep 17 00:00:00 2001 From: Julius Date: Mon, 9 Dec 2013 00:03:07 +0100 Subject: [PATCH 14/14] Improve usability of supplier selection for stock_articles in delivery form --- app/views/deliveries/_form.html.haml | 2 +- .../form_on_stock_article_create.js.erb | 23 +++++++++++-- .../form_on_stock_article_update.js.erb | 33 +++++++++++++++---- config/locales/de.yml | 1 + config/locales/en.yml | 1 + 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml index 533f44c3..a0f1594a 100644 --- a/app/views/deliveries/_form.html.haml +++ b/app/views/deliveries/_form.html.haml @@ -44,7 +44,7 @@ $.ajax({ 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); diff --git a/app/views/deliveries/form_on_stock_article_create.js.erb b/app/views/deliveries/form_on_stock_article_create.js.erb index 25360761..fd1b2d0f 100644 --- a/app/views/deliveries/form_on_stock_article_create.js.erb +++ b/app/views/deliveries/form_on_stock_article_create.js.erb @@ -1,12 +1,31 @@ // Handle more advanced DOM update after AJAX database manipulation. // See publish/subscribe design pattern in /doc. -(function() { +(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); diff --git a/app/views/deliveries/form_on_stock_article_update.js.erb b/app/views/deliveries/form_on_stock_article_update.js.erb index a5a90d94..3d78eb0d 100644 --- a/app/views/deliveries/form_on_stock_article_update.js.erb +++ b/app/views/deliveries/form_on_stock_article_update.js.erb @@ -1,16 +1,35 @@ // Handle more advanced DOM update after AJAX database manipulation. // See publish/subscribe design pattern in /doc. -(function() { +(function(w) { // 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})) %>' - ).addClass('success'); + $('#stock_article_<%= @stock_article.id %>').remove(); - $('#stock_article_<%= @stock_article.id %>').replaceWith(stock_article_for_adding); - updateSort('#stock_articles_for_adding'); + 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 %>); @@ -25,4 +44,4 @@ stock_change_entry.addClass('success'); updateSort('#stock_changes'); -})(); +})(window); diff --git a/config/locales/de.yml b/config/locales/de.yml index 2e5e11a3..d33f5266 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -413,6 +413,7 @@ de: actions: Optionen article: Artikel category: Kategorie + 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 price: Nettopreis diff --git a/config/locales/en.yml b/config/locales/en.yml index 9d7849f6..bf0127b5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -415,6 +415,7 @@ en: actions: Tasks article: Article category: Category + 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 price: Netprice