Port current_orders plugin to current foodsoft

This commit is contained in:
wvengen 2015-04-10 20:25:51 +02:00
parent 5907ff11bb
commit 466e8c5eeb
19 changed files with 114 additions and 108 deletions

View file

@ -1,16 +1,19 @@
FoodsoftCurrentOrders
=====================
Quick support for working with all current orders, to bridge the time until we
have full support for order cycles in foodsoft.
Foodsoft is currently designed to work with one order at a time. In practice,
however there can be multiple orders open at the same time, with one pickup
day. The proper solution to this is to introduce the notion of order cycles,
with each order belonging to a cycle. Until that time, we have this plugin,
with screens for working on all orders that are closed-but-not-finished.
* `current_orders/ordergroups` to edit an ordergroup's order articles for all
orders that are closed but not settled.
* `current_orders/articles` to edit an order article's ordergroups for all
orders that are closed but not settled.
* `current_orders/orders/receive` for a list of orders that can be received.
* `current_orders/orders.pdf?document=(groups|articles)` for PDFs for all
orders that are closed but not settled.
* `current_orders/orders/receive` for a list of orders that can be received.
* `current_orders/articles` to edit an order article's ordergroups in all
orders that are closed but not settled.
* `current_orders/ordergroups` to edit an ordergroup's order articles in all
orders that are closed but not settled.
* `current_orders/group_orders` for all articles in the user's group orders
from orders that are not settled. Can be used as a "shopping-cart overview"
page.
or "checkout" page.

View file

@ -34,10 +34,13 @@ class CurrentOrders::ArticlesController < ApplicationController
else
@order_articles = OrderArticle.where(order_id: @current_orders.all.map(&:id))
end
params[:q] ||= params[:search] # for meta_search instead of ransack
@q = OrderArticle.search(params[:q])
@order_articles = @order_articles.ordered.merge(@q.relation).includes(:article, :article_price)
@order_articles = @order_articles.ordered.merge(@q.result).includes(:article, :article_price)
@order_article = @order_articles.where(id: params[:id]).first
end
helper_method \
def ordergroups_for_adding
Ordergroup.undeleted.order(:name)
end
end

View file

@ -31,7 +31,7 @@ class CurrentOrders::OrdergroupsController < ApplicationController
def find_group_orders
@order_ids = Order.finished_not_closed.map(&:id)
@all_ordergroups = Ordergroup.undeleted.order(:name).all
@all_ordergroups = Ordergroup.undeleted.order(:name).to_a
@ordered_group_ids = GroupOrder.where(order_id: @order_ids).pluck('DISTINCT(ordergroup_id)')
@all_ordergroups.sort_by! {|o| @ordered_group_ids.include?(o.id) ? o.name : "ZZZZZ#{o.name}" }
@ -40,4 +40,8 @@ class CurrentOrders::OrdergroupsController < ApplicationController
where(group_orders: {order_id: @order_ids, ordergroup_id: @ordergroup.id}).ordered.all unless @ordergroup.nil?
end
helper_method \
def articles_for_adding
OrderArticle.includes(:article, :article_price).where(order_id: @order_ids)
end
end

View file

@ -23,7 +23,7 @@ class MultipleOrdersByArticles < OrderPdf
has_units_str = ''
for goa in order_article.group_order_articles.ordered
units = result_in_units(goa, order_article.article)
rows << [show_group(goa.group_order.ordergroup),
rows << [goa.group_order.ordergroup.name,
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity,
goa.result,
units,

View file

@ -74,7 +74,7 @@ class MultipleOrdersByGroups < OrderPdf
rows.first[-1] = nil
end
text show_group(ordergroup), size: fontsize(13), style: :bold
text ordergroup.name, size: fontsize(13), style: :bold
table rows, width: bounds.width, cell_style: {size: fontsize(8), overflow: :shrink_to_fit} do |table|
# borders
table.cells.borders = [:bottom]

View file

@ -6,4 +6,8 @@
- else
%h2= t('current_orders.articles.index.title')
%i#articles_by_articles= t '.no_selection'
#articles_by_articles
%p
%i= t '.counts', ordergroups: Ordergroup.joins(:orders).where(orders: {state: 'finished'}).count(distinct: true), articles: @order_articles.count
%p
%i= t '.no_selection'

View file

@ -5,13 +5,13 @@
-# @todo unduplicate from group_orders's order_article_info
%p
- if order_article.article.manufacturer.blank?
= raw t 'group_orders.order_article_info.supplied_by', supplier: content_tag(:em, supplier_link(order_article.article.supplier))
= raw t '.supplied_by', supplier: content_tag(:em, supplier_link(order_article.article.supplier))
- elsif order_article.article.supplier.name == order_article.article.manufacturer
= raw t 'group_orders.order_article_info.supplied_and_made_by', manufacturer: content_tag(:em, supplier_link(order_article.article.supplier))
= raw t '.supplied_and_made_by', manufacturer: content_tag(:em, supplier_link(order_article.article.supplier))
- else
= raw t 'group_orders.order_article_info.supplied_by_made_by', supplier: content_tag(:em, supplier_link(order_article.article.supplier)), manufacturer: content_tag(:em, order_article.article.manufacturer)
= raw t '.supplied_by_made_by', supplier: content_tag(:em, supplier_link(order_article.article.supplier)), manufacturer: content_tag(:em, order_article.article.manufacturer)
- unless order_article.article.origin.blank?
= raw t 'group_orders.order_article_info.origin_in', origin: content_tag(:em, order_article.article.origin)
= raw t '.origin_in', origin: content_tag(:em, order_article.article.origin)
- pkg_info = pkg_helper(order_article.price)
= ", #{pkg_info}".html_safe unless pkg_info.blank?
@ -19,4 +19,4 @@
= ", "
= Article.human_attribute_name(:fc_price_short) + ": "
= number_to_currency(order_article.price.fc_price)
= t 'current_orders.articles.article_info.unit', unit: order_article.article.unit
= t '.unit', unit: order_article.article.unit

View file

@ -1,4 +1,4 @@
- @order_articles.includes(:order => :supplier).reorder('suppliers.name, articles.article_category_id, articles.name').group_by {|oa| oa.order.name}.each do |name, articles|
%li.nav-header= name
- articles.each do |oa|
%li= link_to oa.article.name, current_orders_articles_path(order: oa.order.id, id: oa.id, anchor: 'order_article'), remote: true
%li= link_to oa.article.name, current_orders_articles_path(order_id: oa.order_id, id: oa.id, anchor: 'order_article'), remote: true

View file

@ -4,9 +4,9 @@
.well
%ul.nav.nav-list#article_list
%li.keep
= form_for @q, url: current_orders_articles_path, method: 'get', html: {data: {'submit-onchange' => true}, class: 'form-search'}, remote: true do |f|
= search_form_for @q, url: current_orders_articles_path, method: 'get', html: {data: {'submit-onchange' => true}, class: 'form-search'}, remote: true do |f|
.input-append
= f.text_field :article_name_contains, placeholder: t('.article_placeholder'), class: 'search-query input-block-level resettable'
= f.text_field :article_name_cont, placeholder: t('.article_placeholder'), class: 'search-query input-block-level resettable'
%button.add-on.btn.reset-search{type: 'button'}
%i.icon.icon-remove
= render 'articles', orders: @current_orders
@ -20,51 +20,55 @@
- content_for :javascript do
:javascript
$(function() {
// update number of received items - would prefer to do this server-side to
// keep working when showing a partial list, but this avoids an extra ajax call
$(document).on('GroupOrderArticle#update #update_articles_summary', function(e) {
var count_sum = 0;
// number of received items
$('#articles_by_articles input[data-delta]').each(function() {
count_sum += Number($(this).val());
});
$('#single_order_article_total .count_sum').html(count_sum);
// delta
// @todo partial code-duplication with orders/_edit_amounts
var expected = $('#single_order_article_delta .units_delta').data('quantity-expected');
var delta = Math.round((count_sum - expected)*100)/100.0;
if (isNaN(delta)) {
html = '';
color = 'inherit';
} else if (delta == 0) {
html = I18n.t('js.current_orders.articles.equal');
color = 'green';
//$('#single_order_article_total .count_sum').html(count_sum + ' <i class="icon-ok"></i>');
} else if (delta < 0) {
html = I18n.t('js.current_orders.articles.below', {count: -delta});
color = 'inherit';
} else {
html = I18n.t('js.current_orders.articles.above', {count: delta});
color = 'red';
}
$('#single_order_article_delta .units_delta').html(html).attr('style', 'color: '+color);
$('#single_order_article_total .count_sum').attr('style', 'color: '+color);
});
// add ordergroup
$('#group_order_article_ordergroup_id').select2().select2('data', null);
$(document).on('GroupOrderArticle#create', function(e) {
var base_unit = $('#articles_by_articles').data('base-unit');
// reset selection
$('#group_order_article_ordergroup_id').select2('data', null);
// update table
$.ajax({
url: '#{show_on_group_order_article_create_current_orders_articles_path}',
type: 'get',
data: {group_order_article_id: e.group_order_article_id, base_unit: base_unit}
});
// update number of received items - would prefer to do this server-side to
// keep working when showing a partial list, but this avoids an extra ajax call
$(document).on('GroupOrderArticle#update #update_articles_summary', function(e) {
var count_sum = 0;
// number of received items
$('#articles_by_articles input[data-delta]').each(function() {
count_sum += Number($(this).val());
});
$('#single_order_article_total .count_sum').html(count_sum);
// delta
// @todo partial code-duplication with orders/_edit_amounts
var expected = $('#single_order_article_delta .units_delta').data('quantity-expected');
var delta = Math.round((count_sum - expected)*100)/100.0;
if (isNaN(delta)) {
html = '';
color = 'inherit';
} else if (delta == 0) {
html = I18n.t('js.current_orders.articles.equal');
color = 'green';
//$('#single_order_article_total .count_sum').html(count_sum + ' <i class="icon-ok"></i>');
} else if (delta < 0) {
html = I18n.t('js.current_orders.articles.below', {count: -delta});
color = 'inherit';
} else {
html = I18n.t('js.current_orders.articles.above', {count: delta});
color = 'red';
}
$('#single_order_article_delta .units_delta').html(html).attr('style', 'color: '+color);
$('#single_order_article_total .count_sum').attr('style', 'color: '+color);
});
$(document).on('#update_articles_summary', function() {
// initialize add ordergroup control
$('#group_order_article_ordergroup_id').select2().select2('data', null);
});
$(function() {
// initialize when loaded as html
$(document).trigger('#update_articles_summary');
});
$(document).on('GroupOrderArticle#create', function(e) {
var base_unit = $('#articles_by_articles').data('base-unit');
// reset selection
$('#group_order_article_ordergroup_id').select2('data', null);
// update table
$.ajax({
url: '#{show_on_group_order_article_create_current_orders_articles_path}',
type: 'get',
data: {group_order_article_id: e.group_order_article_id, base_unit: base_unit}
});
});

View file

@ -1,6 +1,4 @@
- units = order_article.article.unit_unit
- multiplier = (params[:base_unit] and units) ? units.scalar : 1
%table.table.table-hover#articles_by_articles{data: {'base-unit' => params[:base_unit]}}
%table.table.table-hover#articles_by_articles
%thead.list-heading
%tr
%th{:style => 'width:70%'}= Ordergroup.model_name.human
@ -10,9 +8,6 @@
%acronym{:title => t('shared.articles.received_desc')}= t 'shared.articles.received'
%td.center
.btn-group
- if units and units.units != order_article.article.unit
= link_to t('.piece'), current_orders_articles_path(order: order_article.order.id, id: order_article.id), remote: true, class: "btn btn-small #{'active' unless params[:base_unit]}"
= link_to units.units, current_orders_articles_path(order: order_article.order.id, id: order_article.id, base_unit: true), remote: true, class: "btn btn-small #{'active' if params[:base_unit]}"
= render 'shared/articles_by/article_single', order_article: order_article, heading: false, delta_column: true, base_unit: params[:base_unit]
@ -22,16 +17,18 @@
= form_for GroupOrderArticle.new, remote: true, html: {'data-submit-onchange' => true, style: 'margin: 0'} do |f|
= f.hidden_field :order_article_id, value: order_article.id
= f.select :ordergroup_id,
options_for_select(Ordergroup.undeleted.order(:name).all.map { |g| [ show_group(g), g.id ] }),
options_for_select(ordergroups_for_adding.map { |g| [ g.name, g.id ] }),
{include_blank: true}, {style: 'width: 100%', 'data-placeholder' => t('.add_new')}
%td{colspan: 3}
%tr#single_order_article_total
%th= t 'shared.articles_by.price_sum'
%td.center.dimmed #{order_article.quantity*multiplier} + #{order_article.tolerance*multiplier}
%td.center.dimmed #{order_article.quantity} + #{order_article.tolerance}
- sum = order_article.group_orders_sum
%th.center.count_sum= sum[:quantity]*multiplier
%th.center.count_sum= sum[:quantity]
%td
%tr.no-top-border#single_order_article_delta
%td
%td
%td.center
%span.units_delta{data: {'quantity-expected' => order_article.units * order_article.price.unit_quantity * multiplier}}
%span.units_delta{data: {'quantity-expected' => order_article.units * order_article.price.unit_quantity}}
%td

View file

@ -36,7 +36,7 @@
%td
= oa.article.unit
%span{style: 'opacity: 0.4; margin-left: 1em;'}= pkg_helper(oa.price, soft_uq: true)
%td= number_to_currency oa.price.fc_price(@ordergroup)
%td= number_to_currency oa.price.fc_price
%td
= r[:quantity]
= "+ #{r[:tolerance]}" if oa.price.unit_quantity > 1

View file

@ -1,18 +1,12 @@
-# @todo move multiplier to model & unduplicate with shared/articles_by/
- multiplier, unit = 1, '× ' + goa.order_article.article.unit
- if local_assigns[:base_unit] and unit = goa.order_article.article.unit_unit
- multiplier = unit.scalar
- unit = unit.units
-# output row
%tr{:class => [cycle('even', 'odd', :name => 'articles'), if goa.result == 0 then 'unavailable' end], id: "goa_#{goa.id}"}
%td.name= goa.order_article.article.name
%td{title: goa.order_article.order.name}= link_to goa.order_article.order.name.truncate(15), goa.order_article.order
%td= goa.order_article.article.unit
%td.center= "#{goa.quantity} + #{goa.tolerance}"
%td.center.input-delta= group_order_article_edit_result(goa, multiplier: multiplier, edit: local_assigns[:edit]||true)
%td.nowrap.dimmed= unit if multiplier != 1
%td.center.input-delta= group_order_article_edit_result(goa)
%td.symbol
&times;
%td= number_to_currency goa.order_article.price.fc_price(@ordergroup)/multiplier
%td= number_to_currency goa.order_article.price.fc_price
%td.symbol =
%td.price{data: {value: goa.total_price}}= number_to_currency goa.total_price

View file

@ -9,15 +9,9 @@
%acronym{:title => t('shared.articles.ordered_desc')}= t 'shared.articles.ordered'
%th.center{style: 'width: 88px'}
%acronym{:title => t('shared.articles.received_desc')}= t 'shared.articles.received'
%th.nowrap.dimmed
%th.symbol
%th= heading_helper Article, :fc_price, short: true
%th.symbol
%td.center
.btn-group
- if true #if units and units.units != order_article.article.unit
= link_to t('current_orders.articles.ordergroups.piece'), current_orders_ordergroups_path(id: @ordergroup.id), remote: true, class: "btn btn-small #{'active' unless params[:base_unit]}"
= link_to t('current_orders.articles.ordergroups.unit'), current_orders_ordergroups_path(id: @ordergroup.id, base_unit: true), remote: true, class: "btn btn-small #{'active' if params[:base_unit]}"
- total = 0
%tbody.list
@ -28,22 +22,21 @@
- else
%tr
%td{colspan: 11}
%i No articles for #{show_group(@ordergroup)} in the current orders.
%td{colspan: 9}
%i No articles for #{@ordergroup.name} in the current orders.
%tfoot
%tr
%td{colspan: 10}
- new_articles = OrderArticle.includes(:article, :article_price).where(order_id: @order_ids)
- new_article_data = articles_for_select2(new_articles) {|a| "#{a.article.name} (#{a.article.unit}, #{number_to_currency a.price.fc_price})"}
%td{colspan: 9}
- new_article_data = articles_for_select2(articles_for_adding) {|a| "#{a.article.name} (#{a.article.unit}, #{number_to_currency a.price.fc_price})"}
= form_for GroupOrderArticle.new, remote: true, html: {'data-submit-onchange' => true, style: 'margin: 0'} do |f|
= f.select :order_article_id,
options_for_select(new_article_data.map {|a| [a[:text], a[:id]]}),
{}, {style: 'width: 500px', 'data-placeholder' => t('.add_new') }
= f.hidden_field :ordergroup_id, value: @ordergroup.id
%tr#single_ordergroup_total{:class => cycle('even', 'odd', :name => 'articles')}
%th{colspan: 9}= t 'shared.articles_by.price_sum'
%th.price_sum{colspan: 2, data: {value: total}}= number_to_currency(total)
%th{colspan: 8}= t 'shared.articles_by.price_sum'
%th.price_sum{data: {value: total}}= number_to_currency(total)
.well#payment_bar

View file

@ -1,7 +1,7 @@
.well
= form_tag current_orders_ordergroups_path, method: :get, 'data-submit-onchange' => true, style: 'margin: 0' do
= select_tag 'id',
options_for_select(@all_ordergroups.map { |g| [ show_group(g), g.id, {class: ('muted' unless @ordered_group_ids.include? g.id)}] }, (@ordergroup.id rescue '')),
options_for_select(@all_ordergroups.map { |g| [ g.name, g.id, {class: ('muted' unless @ordered_group_ids.include? g.id)}] }, (@ordergroup.id rescue '')),
include_blank: true, id: 'ordergroup_select', style: 'min-width: 300px',
'data-placeholder' => t('.ordergroup_placeholder'), 'data-submit-on-change' => :true
-#.form-search.pull-right # see below why this is disabled
@ -69,4 +69,3 @@
});
*/
});

View file

@ -9,7 +9,6 @@
= link_to 'Account balance', finance_ordergroup_transactions_path(ordergroup)
- else
= t '.account_balance'
of #{show_group(ordergroup)}: #{number_to_currency ordergroup.account_balance}
of #{ordergroup.name}: #{number_to_currency ordergroup.account_balance}
%p#to_pay_message{style: 'text-align: center'}= to_pay_message(ordergroup)

View file

@ -1,3 +1,3 @@
- title t('.title', name: show_group(@ordergroup))
- title t('.title', name: @ordergroup.name)
= render 'form'

View file

@ -1,3 +1,3 @@
// untested
$('h1, title').html('<%= j t('.title', name: show_group(@ordergroup)) %>');
$('h1, title').html('<%= j t('.title', name: @ordergroup.name) %>');
$('#articles_by_groups').html('<%= j render('articles') %>');

View file

@ -2,10 +2,15 @@ en:
current_orders:
articles:
article:
counts: '%{ordergroups} ordergroups ordered %{articles} different articles.'
no_selection: Choose an article to show who ordered it, or download pick lists at the right.
article_info:
from: from %{supplier}
origin_in: in %{origin}
supplied_by: from %{supplier}
supplied_and_made_by: made by %{manufacturer}
supplied_by_made_by: from %{supplier} made by %{manufacturer}
unit: per %{unit}
from: from %{supplier}
form:
article_placeholder: Search articles...
current_orders: All current orders
@ -23,9 +28,9 @@ en:
ordergroups:
articles:
add_new: Add an article...
no_selection: Choose an ordergroup to show the articles.
form:
ordergroup_placeholder: Choose an ordergroup...
no_selection: Choose an ordergroup to show the articles.
index:
title: Articles for ordergroup
payment_bar:

View file

@ -2,6 +2,7 @@ nl:
current_orders:
articles:
article:
counts: '%{ordergroups} huishoudens bestelden %{articles} verschillende artikelen.'
no_selection: Kies een artikel om te zien wie het besteld heeft, of download verdeellijsten rechtsboven.
article_info:
from: van %{supplier}