Merge pull request #373 from foodcoops/feature/current-orders-plugin
Add current_orders plugin
This commit is contained in:
commit
4a9cf862be
47 changed files with 1093 additions and 13 deletions
1
Gemfile
1
Gemfile
|
@ -54,6 +54,7 @@ gem 'foodsoft_wiki', path: 'plugins/wiki'
|
|||
gem 'foodsoft_messages', path: 'plugins/messages'
|
||||
|
||||
# plugins not enabled by default
|
||||
#gem 'foodsoft_current_orders', path: 'plugins/current_orders'
|
||||
#gem 'foodsoft_uservoice', path: 'plugins/uservoice'
|
||||
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ class OrderByArticles < OrderPdf
|
|||
rows << [goa.group_order.ordergroup.name,
|
||||
"#{goa.quantity} + #{goa.tolerance}",
|
||||
goa.result,
|
||||
number_with_precision(order_article.price.fc_price * goa.result, precision: 2)]
|
||||
number_to_currency(goa.total_price(order_article))]
|
||||
dimrows << rows.length if goa.result == 0
|
||||
end
|
||||
next if rows.length == 0
|
||||
rows.unshift I18n.t('documents.order_by_articles.rows') # table header
|
||||
|
||||
text "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity.to_s} | #{number_with_precision(order_article.price.fc_price, precision: 2)})",
|
||||
text "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity.to_s} | #{number_to_currency(order_article.price.fc_price)})",
|
||||
style: :bold, size: fontsize(10)
|
||||
table rows, cell_style: {size: fontsize(8), overflow: :shrink_to_fit} do |table|
|
||||
table.column(0).width = 200
|
||||
|
@ -36,7 +36,10 @@ class OrderByArticles < OrderPdf
|
|||
table.cells.border_color = '666666'
|
||||
table.rows(0).border_bottom_width = 2
|
||||
# dim rows which were ordered but not received
|
||||
dimrows.each { |ri| table.row(ri).text_color = '999999' }
|
||||
dimrows.each do |ri|
|
||||
table.row(ri).text_color = '999999'
|
||||
table.row(ri).columns(0..-1).font_style = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,26 +25,30 @@ class OrderByGroups < OrderPdf
|
|||
sub_total = price * goa.result
|
||||
total += sub_total
|
||||
rows << [goa.order_article.article.name,
|
||||
"#{goa.quantity} + #{goa.tolerance}",
|
||||
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity,
|
||||
goa.result,
|
||||
number_with_precision(price, precision: 2),
|
||||
number_to_currency(price),
|
||||
goa.order_article.price.unit_quantity,
|
||||
goa.order_article.article.unit,
|
||||
number_with_precision(sub_total, precision: 2)]
|
||||
number_to_currency(sub_total)]
|
||||
dimrows << rows.length if goa.result == 0
|
||||
end
|
||||
next if rows.length == 0
|
||||
rows << [ I18n.t('documents.order_by_groups.sum'), nil, nil, nil, nil, nil, number_with_precision(total, precision: 2)]
|
||||
rows << [ I18n.t('documents.order_by_groups.sum'), nil, nil, nil, nil, nil, number_to_currency(total)]
|
||||
rows.unshift I18n.t('documents.order_by_groups.rows') # Table Header
|
||||
|
||||
text group_order.ordergroup.name, size: fontsize(9), style: :bold
|
||||
table rows, width: 500, cell_style: {size: fontsize(8), overflow: :shrink_to_fit} do |table|
|
||||
# borders
|
||||
table.cells.borders = []
|
||||
table.row(0).borders = [:bottom]
|
||||
table.row(group_order_articles.size).borders = [:bottom]
|
||||
table.cells.border_width = 1
|
||||
table.cells.border_color = '666666'
|
||||
table.cells.borders = [:bottom]
|
||||
table.cells.border_width = 0.02
|
||||
table.cells.border_color = 'dddddd'
|
||||
table.rows(0).border_width = 1
|
||||
table.rows(0).border_color = '666666'
|
||||
table.rows(0).column(5).font_style = :bold
|
||||
table.row(rows.length-2).border_width = 1
|
||||
table.row(rows.length-2).border_color = '666666'
|
||||
table.row(rows.length-1).borders = []
|
||||
|
||||
table.column(0).width = 240
|
||||
table.column(2).font_style = :bold
|
||||
|
@ -53,7 +57,10 @@ class OrderByGroups < OrderPdf
|
|||
table.column(6).font_style = :bold
|
||||
|
||||
# dim rows which were ordered but not received
|
||||
dimrows.each { |ri| table.row(ri).text_color = '999999' }
|
||||
dimrows.each do |ri|
|
||||
table.row(ri).text_color = '999999'
|
||||
table.row(ri).columns(0..-1).font_style = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1680,6 +1680,7 @@ nl:
|
|||
title_all: Alle groepstaken
|
||||
ui:
|
||||
actions: Acties
|
||||
back: Terug
|
||||
cancel: Annuleren
|
||||
close: Sluiten
|
||||
copy: Kopiëren
|
||||
|
|
42
plugins/current_orders/README.md
Normal file
42
plugins/current_orders/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
FoodsoftCurrentOrders
|
||||
=====================
|
||||
|
||||
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.
|
||||
|
||||
Important: be sure to settle orders from the previous order cycle, before
|
||||
you close any. If you don't, articles from previous and current dates start
|
||||
to mix up (if you do, settle the old ones asap).
|
||||
|
||||
* `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/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"
|
||||
or "checkout" page.
|
||||
|
||||
New menu items will be added in the "Orders" menu. Please note that members
|
||||
with _Orders_ permission will now be able to edit the amounts members received
|
||||
in some of these screens, something that was previously restricted to the
|
||||
_Finance_ permission.
|
||||
|
||||
This plugin is not enabled by default. To install it, add uncomment the
|
||||
corresponding line in the `Gemfile`, or add:
|
||||
|
||||
```Gemfile
|
||||
gem 'foodsoft_current_orders', path: 'plugins/current_orders'
|
||||
```
|
||||
|
||||
This plugin introduces the foodcoop config option `use_current_orders`, which
|
||||
needs to be set to `true` to enable the plugin. This can be done in the
|
||||
configuration screen or `config/app_config.yml`.
|
||||
|
||||
This plugin is part of the foodsoft package and uses the GPL-3 license or later
|
||||
(see foodsoft's LICENSE for the full license text).
|
|
@ -0,0 +1,46 @@
|
|||
# encoding: utf-8
|
||||
class CurrentOrders::ArticlesController < ApplicationController
|
||||
|
||||
before_filter :authenticate_orders
|
||||
before_filter :find_order_and_order_article, only: [:index, :show]
|
||||
|
||||
def index
|
||||
# sometimes need to pass id as parameter for forms
|
||||
show if @order_article
|
||||
end
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html { render :show }
|
||||
format.js { render :show, layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def show_on_group_order_article_create
|
||||
@goa = GroupOrderArticle.find(params[:group_order_article_id])
|
||||
end
|
||||
|
||||
def show_on_group_order_article_update
|
||||
#@goa = GroupOrderArticle.find(params[:group_order_article_id])
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_order_and_order_article
|
||||
@current_orders = Order.finished_not_closed
|
||||
unless params[:order_id].blank?
|
||||
@order = Order.find(params[:order_id])
|
||||
@order_articles = @order.order_articles
|
||||
else
|
||||
@order_articles = OrderArticle.where(order_id: @current_orders.all.map(&:id))
|
||||
end
|
||||
@q = OrderArticle.search(params[:q])
|
||||
@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
|
|
@ -0,0 +1,26 @@
|
|||
class CurrentOrders::GroupOrdersController < ApplicationController
|
||||
# Security
|
||||
before_filter :ensure_ordergroup_member
|
||||
|
||||
def index
|
||||
# XXX code duplication lib/foodsoft_current_orders/app/controllers/current_orders/ordergroups_controller.rb
|
||||
@order_ids = Order.where(state: ['open', 'finished']).all.map(&:id)
|
||||
@goas = GroupOrderArticle.includes(:group_order => :ordergroup).includes(:order_article).
|
||||
where(group_orders: {order_id: @order_ids, ordergroup_id: @ordergroup.id}).ordered
|
||||
@articles_grouped_by_category = @goas.includes(:order_article => {:article => :article_category}).
|
||||
order('articles.name').
|
||||
group_by { |a| a.order_article.article.article_category.name }.
|
||||
sort { |a, b| a[0] <=> b[0] }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# XXX code duplication from GroupOrdersController
|
||||
def ensure_ordergroup_member
|
||||
@ordergroup = @current_user.ordergroup
|
||||
if @ordergroup.nil?
|
||||
redirect_to root_url, :alert => I18n.t('group_orders.errors.no_member')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
# encoding: utf-8
|
||||
class CurrentOrders::OrdergroupsController < ApplicationController
|
||||
|
||||
before_filter :authenticate_orders
|
||||
before_filter :find_group_orders, only: [:index, :show]
|
||||
|
||||
def index
|
||||
# sometimes need to pass id as parameter for forms
|
||||
render 'show' if @ordergroup
|
||||
end
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html { render :show }
|
||||
format.js { render :show, layout: false }
|
||||
end
|
||||
end
|
||||
|
||||
def show_on_group_order_article_create
|
||||
@goa = GroupOrderArticle.find(params[:group_order_article_id])
|
||||
end
|
||||
|
||||
def show_on_group_order_article_update
|
||||
#@goa = GroupOrderArticle.find(params[:group_order_article_id])
|
||||
@group_order = GroupOrder.find(params[:group_order_id])
|
||||
@ordergroup = @group_order.ordergroup
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_group_orders
|
||||
@order_ids = Order.finished_not_closed.map(&:id)
|
||||
|
||||
@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}" }
|
||||
|
||||
@ordergroup = Ordergroup.find(params[:id]) unless params[:id].nil?
|
||||
@goas = GroupOrderArticle.includes(:group_order, :order_article => [:article, :article_price]).
|
||||
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
|
|
@ -0,0 +1,40 @@
|
|||
class CurrentOrders::OrdersController < ApplicationController
|
||||
|
||||
before_filter :authenticate_orders, except: :my
|
||||
|
||||
def show
|
||||
@doc_options ||= {}
|
||||
@order_ids = if params[:id]
|
||||
params[:id].split('+').map(&:to_i)
|
||||
else
|
||||
Order.finished_not_closed.all.map(&:id)
|
||||
end
|
||||
@view = (params[:view] or 'default').gsub(/[^-_a-zA-Z0-9]/, '')
|
||||
|
||||
respond_to do |format|
|
||||
format.pdf do
|
||||
pdf = case params[:document]
|
||||
when 'groups' then MultipleOrdersByGroups.new(@order_ids, @doc_options)
|
||||
when 'articles' then MultipleOrdersByArticles.new(@order_ids, @doc_options)
|
||||
end
|
||||
send_data pdf.to_pdf, filename: pdf.filename, type: 'application/pdf'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def my
|
||||
@doc_options ||= {}
|
||||
@doc_options[:ordergroup] = @current_user.ordergroup.id
|
||||
respond_to do |format|
|
||||
format.pdf do
|
||||
params[:document] = 'groups'
|
||||
show
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def receive
|
||||
@orders = Order.finished_not_closed.includes(:supplier)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
# encoding: utf-8
|
||||
class CurrentOrdersController < ApplicationController
|
||||
|
||||
before_filter :authenticate_orders
|
||||
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
# encoding: utf-8
|
||||
class MultipleOrdersByArticles < OrderPdf
|
||||
include OrdersHelper
|
||||
|
||||
def filename
|
||||
I18n.t('documents.multiple_orders_by_articles.filename', count: @order.count) + '.pdf'
|
||||
end
|
||||
|
||||
def title
|
||||
I18n.t('documents.multiple_orders_by_articles.title', count: @order.count)
|
||||
end
|
||||
|
||||
def order_articles
|
||||
@order_articles ||= OrderArticle.joins(:order, :article).where(:orders => {:id => @order}).ordered.reorder('orders.id, articles.name')
|
||||
end
|
||||
|
||||
# @todo refactor to reduce common code with order_by_articles
|
||||
def body
|
||||
order_articles.each do |order_article|
|
||||
down_or_page
|
||||
|
||||
rows = []
|
||||
dimrows = []
|
||||
has_units_str = ''
|
||||
for goa in order_article.group_order_articles.ordered
|
||||
rows << [goa.group_order.ordergroup.name,
|
||||
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity,
|
||||
goa.result,
|
||||
number_to_currency(goa.total_price(order_article))]
|
||||
dimrows << rows.length if goa.result == 0
|
||||
end
|
||||
next if rows.length == 0
|
||||
sum = order_article.group_orders_sum
|
||||
rows.unshift I18n.t('documents.order_by_articles.rows').dup # table header
|
||||
|
||||
rows << [I18n.t('documents.order_by_groups.sum'),
|
||||
order_article.tolerance > 0 ? "#{order_article.quantity} + #{order_article.tolerance}" : order_article.quantity,
|
||||
sum[:quantity],
|
||||
nil] #number_to_currency(sum[:price])]
|
||||
|
||||
text "<b>#{order_article.article.name}</b> " +
|
||||
"(#{order_article.article.unit}; #{number_to_currency order_article.price.fc_price}; " +
|
||||
units_history_line(order_article, plain: true) + ')',
|
||||
size: fontsize(10), inline_format: true
|
||||
table rows, cell_style: {size: fontsize(8), overflow: :shrink_to_fit} do |table|
|
||||
# borders
|
||||
table.cells.borders = [:bottom]
|
||||
table.cells.border_width = 0.02
|
||||
table.cells.border_color = 'dddddd'
|
||||
table.rows(0).border_width = 1
|
||||
table.rows(0).border_color = '666666'
|
||||
table.row(rows.length-2).border_width = 1
|
||||
table.row(rows.length-2).border_color = '666666'
|
||||
table.row(rows.length-1).borders = []
|
||||
|
||||
table.column(0).width = 200
|
||||
table.columns(1..2).align = :center
|
||||
table.column(2).font_style = :bold
|
||||
table.columns(3).align = :right
|
||||
|
||||
# dim rows which were ordered but not received
|
||||
dimrows.each { |ri| table.row(ri).text_color = '999999' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def pdf_add_page_breaks?
|
||||
super 'order_by_articles'
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,106 @@
|
|||
# encoding: utf-8
|
||||
class MultipleOrdersByGroups < OrderPdf
|
||||
include OrdersHelper
|
||||
|
||||
def filename
|
||||
I18n.t('documents.multiple_orders_by_groups.filename', count: @order.count) + '.pdf'
|
||||
end
|
||||
|
||||
def title
|
||||
I18n.t('documents.multiple_orders_by_groups.title', count: @order.count)
|
||||
end
|
||||
|
||||
def ordergroups
|
||||
unless @ordergroups
|
||||
@ordergroups = Ordergroup.joins(:orders).where(orders: {id: @order}).select('distinct(groups.id)').select('groups.*').reorder(:name)
|
||||
@ordergroups = @ordergroups.where(id: @options[:ordergroup]) if @options[:ordergroup]
|
||||
end
|
||||
@ordergroups
|
||||
end
|
||||
|
||||
# @todo refactor to reduce common code with order_by_groups
|
||||
def body
|
||||
# Start rendering
|
||||
ordergroups.each do |ordergroup|
|
||||
down_or_page 15
|
||||
|
||||
total = 0
|
||||
taxes = Hash.new {0}
|
||||
rows = []
|
||||
dimrows = []
|
||||
group_order_articles = GroupOrderArticle.ordered.joins(:group_order => :order).where(:group_orders =>{:ordergroup_id => ordergroup.id}).where(:orders => {id: @order}).includes(:order_article => :article_price).reorder('orders.id')
|
||||
has_tolerance = group_order_articles.where('article_prices.unit_quantity > 1').any?
|
||||
|
||||
group_order_articles.each do |goa|
|
||||
price = goa.order_article.price.fc_price
|
||||
sub_total = goa.total_price
|
||||
total += sub_total
|
||||
rows << [goa.order_article.article.name,
|
||||
goa.group_order.order.name.truncate(10, omission: ''),
|
||||
number_to_currency(price),
|
||||
goa.order_article.article.unit,
|
||||
goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity,
|
||||
goa.result,
|
||||
number_to_currency(sub_total),
|
||||
(goa.order_article.price.unit_quantity if has_tolerance)]
|
||||
dimrows << rows.length if goa.result == 0
|
||||
end
|
||||
next if rows.length == 0
|
||||
|
||||
# total
|
||||
rows << [{content: I18n.t('documents.order_by_groups.sum'), colspan: 6}, number_to_currency(total), nil]
|
||||
|
||||
# table header
|
||||
rows.unshift [
|
||||
OrderArticle.human_attribute_name(:article),
|
||||
Article.human_attribute_name(:supplier),
|
||||
I18n.t('documents.order_by_groups.rows')[3],
|
||||
Article.human_attribute_name(:unit),
|
||||
I18n.t('shared.articles.ordered'),
|
||||
I18n.t('shared.articles.received'),
|
||||
I18n.t('shared.articles_by.price_sum'),
|
||||
has_tolerance ? {image: "#{Rails.root}/app/assets/images/package-bg.png", scale: 0.6, position: :center} : nil
|
||||
]
|
||||
|
||||
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]
|
||||
table.cells.border_width = 0.02
|
||||
table.cells.border_color = 'dddddd'
|
||||
table.rows(0).border_width = 1
|
||||
table.rows(0).border_color = '666666'
|
||||
table.rows(0).column(5).font_style = :bold
|
||||
table.row(rows.length-2).border_width = 1
|
||||
table.row(rows.length-2).border_color = '666666'
|
||||
table.row(rows.length-1).borders = []
|
||||
|
||||
table.column(0).width = 180 # @todo would like to set minimum width here
|
||||
table.column(1).width = 62
|
||||
table.column(2).align = :right
|
||||
table.column(5..6).font_style = :bold
|
||||
table.columns(3..5).align = :center
|
||||
table.column(6).align = :right
|
||||
table.column(7).align = :center
|
||||
# dim rows not relevant for members
|
||||
table.column(4).text_color = '999999'
|
||||
table.column(7).text_color = '999999'
|
||||
# hide unit_quantity if there's no tolerance anyway
|
||||
table.column(-1).width = has_tolerance ? 20 : 0
|
||||
|
||||
# dim rows which were ordered but not received
|
||||
dimrows.each do |ri|
|
||||
table.row(ri).text_color = 'aaaaaa'
|
||||
table.row(ri).columns(0..-1).font_style = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def pdf_add_page_breaks?
|
||||
super 'order_by_groups'
|
||||
end
|
||||
|
||||
end
|
14
plugins/current_orders/app/helpers/current_orders_helper.rb
Normal file
14
plugins/current_orders/app/helpers/current_orders_helper.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
module CurrentOrdersHelper
|
||||
|
||||
def to_pay_message(ordergroup)
|
||||
funds = ordergroup.get_available_funds
|
||||
if funds > 0
|
||||
content_tag :b, I18n.t('helpers.current_orders.pay_done'), style: 'color: green'
|
||||
elsif funds == 0
|
||||
I18n.t('helpers.current_orders.pay_none')
|
||||
else
|
||||
content_tag :b, I18n.t('helpers.current_orders.pay_amount', amount: number_to_currency(-ordergroup.get_available_funds))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains(":use_nick")'
|
||||
= config_input form, :use_current_orders, as: :boolean
|
|
@ -0,0 +1,8 @@
|
|||
/ insert_before '#articles_table'
|
||||
- if FoodsoftCurrentOrders.enabled?
|
||||
- unless @orders.nil? or @orders.empty? or @order_articles.nil? or @order_articles.empty?
|
||||
- content_for :actionbar do
|
||||
= link_to url_for(controller: 'current_orders/orders', action: 'my', id: @orders.map(&:id).join('+'), format: 'pdf'), class: 'btn' do
|
||||
= glyph :download
|
||||
PDF
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/ insert_before 'h2:contains(".orders_finished")'
|
||||
- if FoodsoftCurrentOrders.enabled?
|
||||
.btn-group.pull-right#orders_finished_toolbar
|
||||
= link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
|
||||
= t 'orders.show.download.title'
|
||||
%span.caret
|
||||
%ul.dropdown-menu
|
||||
%li= link_to t('orders.show.download.group_pdf'), current_orders_orders_path(document: :groups, format: :pdf)
|
||||
%li= link_to t('orders.show.download.article_pdf'), current_orders_orders_path(document: :articles, format: :pdf)
|
|
@ -0,0 +1,7 @@
|
|||
.btn-group.pull-right
|
||||
= link_to '#', data: {toggle: 'dropdown'}, class: 'btn dropdown-toggle' do
|
||||
= t 'orders.show.download.title'
|
||||
%span.caret
|
||||
%ul.dropdown-menu
|
||||
%li= link_to t('orders.show.download.group_pdf'), current_orders_orders_path(document: :groups, format: :pdf)
|
||||
%li= link_to t('orders.show.download.article_pdf'), current_orders_orders_path(document: :articles, format: :pdf)
|
|
@ -0,0 +1,13 @@
|
|||
#order_article
|
||||
|
||||
- if order_article
|
||||
= render 'article_info', order_article: order_article
|
||||
= render 'ordergroups', order_article: order_article
|
||||
|
||||
- else
|
||||
%h2= t('current_orders.articles.index.title')
|
||||
#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'
|
|
@ -0,0 +1,22 @@
|
|||
#article_info
|
||||
%h2{style: 'margin-bottom: 0'}
|
||||
= t('current_orders.articles.show.title', name: order_article.article.name)
|
||||
%span.normal= order_article.article.unit
|
||||
-# @todo unduplicate from group_orders's order_article_info
|
||||
%p
|
||||
- if order_article.article.manufacturer.blank?
|
||||
= 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 '.supplied_and_made_by', manufacturer: content_tag(:em, supplier_link(order_article.article.supplier))
|
||||
- else
|
||||
= 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 '.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?
|
||||
|
||||
= ", "
|
||||
= Article.human_attribute_name(:fc_price_short) + ": "
|
||||
= number_to_currency(order_article.price.fc_price)
|
||||
= t '.unit', unit: order_article.article.unit
|
|
@ -0,0 +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_id: oa.order_id, id: oa.id, anchor: 'order_article'), remote: true
|
|
@ -0,0 +1,74 @@
|
|||
.row-fluid
|
||||
|
||||
.span4
|
||||
.well
|
||||
%ul.nav.nav-list#article_list
|
||||
%li.keep
|
||||
= 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_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
|
||||
|
||||
.span8
|
||||
= render 'actions'
|
||||
= render 'article', order_article: @order_article
|
||||
= render 'shared/articles_by/common'
|
||||
|
||||
|
||||
- content_for :javascript do
|
||||
:javascript
|
||||
|
||||
// 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}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
%table.table.table-hover#articles_by_articles
|
||||
%thead.list-heading
|
||||
%tr
|
||||
%th{:style => 'width:70%'}= Ordergroup.model_name.human
|
||||
%th.center.dimmed
|
||||
%acronym{:title => t('shared.articles.ordered_desc')}= t 'shared.articles.ordered'
|
||||
%th.center
|
||||
%acronym{:title => t('shared.articles.received_desc')}= t 'shared.articles.received'
|
||||
%td.center
|
||||
.btn-group
|
||||
|
||||
= render 'shared/articles_by/article_single', order_article: order_article, heading: false, delta_column: true, base_unit: params[:base_unit]
|
||||
|
||||
%tfoot
|
||||
%tr
|
||||
%td
|
||||
= 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(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} + #{order_article.tolerance}
|
||||
- sum = order_article.group_orders_sum
|
||||
%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}}
|
||||
%td
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title'), false
|
||||
|
||||
= render 'form'
|
|
@ -0,0 +1,2 @@
|
|||
$('#article_list li:not(.keep)').remove();
|
||||
$('#article_list').append('<%= j(render('articles', orders: @current_orders)) %>');
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title', name: @order_article.article.name), false
|
||||
|
||||
= render 'form'
|
|
@ -0,0 +1,3 @@
|
|||
$('#order_article').replaceWith('<%= j(render('article', order_article: @order_article)) if @order_article %>');
|
||||
// add javascript improvements (delta)
|
||||
$(document).trigger('#update_articles_summary');
|
|
@ -0,0 +1,7 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function(w) {
|
||||
$('#goa_<%= @goa.id %>').remove(); // just to be sure: remove table row which is added below
|
||||
$('#articles_by_articles tbody').append('<%= j render('shared/articles_by/article_single_goa', goa: @goa, base_unit: params[:base_unit]) %>').addClass('success');
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
.pull-right
|
||||
= link_to t('ui.back'), root_path(anchor: ''), class: 'btn'
|
||||
|
||||
%p.pull-left
|
||||
= link_to t('current_orders.ordergroups.payment_bar.account_balance'), my_ordergroup_path
|
||||
= number_to_currency (ordergroup.account_balance)
|
||||
|
||||
%p#to_pay_message{style: 'text-align: center'}= to_pay_message(ordergroup)
|
|
@ -0,0 +1,55 @@
|
|||
-# XXX code duplication of foodcoop-adam's app/views/group_orders/show.html.haml
|
||||
- if @articles_grouped_by_category.count > 0
|
||||
%table.table.table-hover
|
||||
%thead
|
||||
%tr
|
||||
%th{style: "width:40%"}= heading_helper Article, :name
|
||||
%th= heading_helper Article, :unit
|
||||
%th= t 'group_orders.show.articles.unit_price'
|
||||
%th
|
||||
%abbr{title: t('group_orders.show.articles.ordered_title')}= t 'group_orders.show.articles.ordered'
|
||||
%th
|
||||
%abbr{title: t('group_orders.show.articles.order_nopen_title')}
|
||||
- if (@order.open? rescue true)
|
||||
= t 'group_orders.show.articles.order_open'
|
||||
- else
|
||||
= t 'group_orders.show.articles.order_not_open'
|
||||
%th= heading_helper GroupOrderArticle, :total_price
|
||||
%tbody
|
||||
- group_order_sum = 0
|
||||
- for category_name, goas in @articles_grouped_by_category
|
||||
%tr.article-category.list-heading
|
||||
%td
|
||||
= category_name
|
||||
%i.icon-tag
|
||||
%td{colspan: "9"}
|
||||
- goas.each do |goa|
|
||||
- # get the order-results for the ordergroup
|
||||
- oa = goa.order_article
|
||||
- r = {quantity: goa.quantity, tolerance: goa.tolerance, result: goa.result, sub_total: goa.total_price(oa)}
|
||||
- group_order_sum += r[:sub_total]
|
||||
%tr{class: cycle('even', 'odd', name: 'articles') + " order-article " + order_article_class_name(r[:quantity], r[:tolerance], r[:result])}
|
||||
-# article_info is present in foodcoop-adam only
|
||||
%td.name{style: "width:40%", title: (article_info_title(oa.article) rescue nil)}
|
||||
= article_info_icon oa.article rescue nil
|
||||
= oa.article.name
|
||||
%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
|
||||
%td
|
||||
= r[:quantity]
|
||||
= "+ #{r[:tolerance]}" if oa.price.unit_quantity > 1
|
||||
%td= r[:result] > 0 ? r[:result] : "0"
|
||||
%td= number_to_currency(r[:sub_total])
|
||||
- unless oa.article.note.blank?
|
||||
%tr{id: "note_#{oa.id}", class: "note even", style: "display:none"}
|
||||
%td{colspan: "6"}=h oa.article.note
|
||||
%tr{class: cycle('even', 'odd', name: 'articles')}
|
||||
%th{colspan: "5"}= heading_helper GroupOrder, :price
|
||||
%th= number_to_currency(group_order_sum)
|
||||
- elsif @articles_grouped_by_category.count == 0
|
||||
= t 'group_orders.show.articles.no_articles'
|
||||
- else
|
||||
= t 'group_orders.show.articles.order_closed_msg'
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
- title t('.title')
|
||||
|
||||
// Article box
|
||||
%section
|
||||
.column_content#result
|
||||
= render 'result'
|
||||
|
||||
.well
|
||||
= render 'payment_bar', ordergroup: @ordergroup
|
||||
|
||||
%br/
|
||||
= link_to_top
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
-# 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)
|
||||
%td.symbol
|
||||
×
|
||||
%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
|
|
@ -0,0 +1,46 @@
|
|||
- if @ordergroup
|
||||
%table.table.table-hover#articles_by_groups_table{data: {'base-unit' => params[:base_unit]}}
|
||||
%thead
|
||||
%tr
|
||||
%th{style: 'width: 35%'}= heading_helper Article, :name
|
||||
%th= Order.model_name.human
|
||||
%th= heading_helper Article, :unit
|
||||
%th.center
|
||||
%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.symbol
|
||||
%th= heading_helper Article, :fc_price, short: true
|
||||
%th.symbol
|
||||
|
||||
- total = 0
|
||||
%tbody.list
|
||||
- if @goas and @goas.length > 0
|
||||
- for goa in @goas
|
||||
- total += goa.total_price
|
||||
= render 'article', goa: goa, base_unit: params[:base_unit]
|
||||
|
||||
- else
|
||||
%tr
|
||||
%td{colspan: 9}
|
||||
%i No articles for #{@ordergroup.name} in the current orders.
|
||||
|
||||
%tfoot
|
||||
%tr
|
||||
%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: 8}= t 'shared.articles_by.price_sum'
|
||||
%th.price_sum{data: {value: total}}= number_to_currency(total)
|
||||
|
||||
|
||||
.well#payment_bar
|
||||
= render 'payment_bar', ordergroup: @ordergroup
|
||||
|
||||
- else
|
||||
%i= t '.no_selection'
|
|
@ -0,0 +1,71 @@
|
|||
.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| [ 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
|
||||
.input-append
|
||||
= text_field_tag :query, params[:query], class: 'search-query delayed-search resettable', disabled: @ordergroup.nil?,
|
||||
'placeholder' => t('orders.show.search_placeholder.articles')
|
||||
%button.add-on.btn.reset-search{:type => :button, :title => t('orders.show.search_reset')}
|
||||
%i.icon.icon-remove
|
||||
|
||||
|
||||
- if @ordergroup and FoodsoftConfig[:price_markup_list]
|
||||
%span.price_markup_note{style: 'margin-left: 1em'}= show_price_markup @ordergroup, format: :full_label, optional: true
|
||||
|
||||
#articles_by_groups
|
||||
= render 'articles'
|
||||
|
||||
= render 'shared/articles_by/common', order: @order
|
||||
|
||||
|
||||
- content_for :javascript do
|
||||
:javascript
|
||||
|
||||
$(function() {
|
||||
// TODO group by ordered / not-ordered
|
||||
$('#ordergroup_select').select2();
|
||||
|
||||
// add article
|
||||
$('#group_order_article_order_article_id').select2({
|
||||
placeholder: '#{j t('orders.receive.add_article')}',
|
||||
formatNoMatches: function(term) { return '#{j t('.no_articles_available')}';}
|
||||
});
|
||||
$(document).on('GroupOrderArticle#create', function(e) {
|
||||
var base_unit = $('#articles_by_groups_table').data('base-unit');
|
||||
// reset selection
|
||||
$('#group_order_article_order_article_id').select2('data', null);
|
||||
// update table
|
||||
$.ajax({
|
||||
url: '#{show_on_group_order_article_create_current_orders_ordergroups_path}',
|
||||
type: 'get',
|
||||
data: {group_order_article_id: e.group_order_article_id, base_unit: base_unit}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('GroupOrderArticle#update', function(e) {
|
||||
$.ajax({
|
||||
url: '#{show_on_group_order_article_update_current_orders_ordergroups_path}',
|
||||
type: 'get',
|
||||
data: {group_order_id: e.group_order_id, group_order_article_id: e.group_order_article_id}
|
||||
});
|
||||
});
|
||||
|
||||
// article search
|
||||
// DO NOT USE because listjs can't handle updates https://github.com/javve/list.js/issues/86
|
||||
/*
|
||||
new List(document.body, {
|
||||
valueNames: ['name'],
|
||||
engine: 'unlist',
|
||||
plugins: [
|
||||
['reset', {highlightClass: 'btn-primary'}],
|
||||
['delay', {delayedSearchTime: 500}],
|
||||
],
|
||||
// make large pages work too (as we don't have paging)
|
||||
page: 10000,
|
||||
indexAsync: true
|
||||
});
|
||||
*/
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
- if current_user.role_finance?
|
||||
.pull-right
|
||||
= t('.payment')
|
||||
- if current_user.role_finance?
|
||||
= link_to t('.new_transaction'), new_finance_ordergroup_transaction_path(ordergroup), class: 'btn'
|
||||
|
||||
%p.pull-left
|
||||
- if current_user.role_finance?
|
||||
= link_to 'Account balance', finance_ordergroup_transactions_path(ordergroup)
|
||||
- else
|
||||
= t '.account_balance'
|
||||
of #{ordergroup.name}: #{number_to_currency ordergroup.account_balance}
|
||||
|
||||
%p#to_pay_message{style: 'text-align: center'}= to_pay_message(ordergroup)
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title')
|
||||
|
||||
= render 'form'
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title', name: @ordergroup.name)
|
||||
|
||||
= render 'form'
|
|
@ -0,0 +1,3 @@
|
|||
// untested
|
||||
$('h1, title').html('<%= j t('.title', name: @ordergroup.name) %>');
|
||||
$('#articles_by_groups').html('<%= j render('articles') %>');
|
|
@ -0,0 +1,7 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function(w) {
|
||||
$('#goa_<%= @goa.id %>').remove(); // just to be sure: remove table row which is added below
|
||||
$('#articles_by_groups tbody').append('<%= j render('article', goa: @goa, base_unit: params[:base_unit]) %>').addClass('success');
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Handle more advanced DOM update after AJAX database manipulation.
|
||||
// See publish/subscribe design pattern in /doc.
|
||||
(function(w) {
|
||||
// table update is done by group_order_article hook already
|
||||
$('#to_pay_message').html('<%= j to_pay_message(@ordergroup) %>');
|
||||
})(window);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
- title t('.title')
|
||||
|
||||
.well
|
||||
- if @orders.empty?
|
||||
= t '.no_finished_orders'
|
||||
- else
|
||||
%table.table.table-striped
|
||||
%thead
|
||||
%tr
|
||||
%th= heading_helper Order, :name
|
||||
%th= heading_helper Order, :ends
|
||||
%th= heading_helper Order, :note
|
||||
%th{colspan: "2"}
|
||||
%tbody
|
||||
- for order in @orders
|
||||
%tr
|
||||
%td= order.name
|
||||
%td= format_time(order.ends)
|
||||
%td= truncate(order.note)
|
||||
%td= receive_button order, class: 'btn-small' unless order.stockit?
|
||||
%td
|
||||
= link_to t('ui.show'), order, class: 'btn btn-small'
|
||||
= order_pdf order, :fax, t('orders.show.download.fax_pdf'), class: 'btn btn-small'
|
||||
|
73
plugins/current_orders/config/locales/en.yml
Normal file
73
plugins/current_orders/config/locales/en.yml
Normal file
|
@ -0,0 +1,73 @@
|
|||
en:
|
||||
config:
|
||||
hints:
|
||||
use_current_orders: Enable the current_orders plugin. Allows members with the order permission to change member amounts in multiple orders, using three new screens in the Orders menu. Especially useful for pick-up days.
|
||||
keys:
|
||||
use_current_orders: Extra distribute screens
|
||||
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:
|
||||
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
|
||||
index:
|
||||
title: Distribute articles
|
||||
ordergroups:
|
||||
piece: pc
|
||||
unit: unit
|
||||
add_new: Add an ordergroup...
|
||||
show:
|
||||
title: ! '%{name}'
|
||||
navigation:
|
||||
receive: Receive
|
||||
articles: Distribute
|
||||
ordergroups: Member orders
|
||||
group_orders:
|
||||
index:
|
||||
title: Your current orders
|
||||
ordergroups:
|
||||
articles:
|
||||
add_new: Add an article...
|
||||
no_selection: Choose an ordergroup to show the articles.
|
||||
form:
|
||||
ordergroup_placeholder: Choose an ordergroup...
|
||||
index:
|
||||
title: Articles for ordergroup
|
||||
payment_bar:
|
||||
account_balance: Account balance
|
||||
new_pin: PIN
|
||||
new_transaction: New transaction
|
||||
payment: ! 'Payment:'
|
||||
show:
|
||||
title: Articles for %{name}
|
||||
orders:
|
||||
receive:
|
||||
title: Receive orders
|
||||
no_finished_orders: There are currently no orders to receive.
|
||||
documents:
|
||||
multiple_orders_by_articles:
|
||||
filename: Current orders sorted by article
|
||||
title: Current orders - by article
|
||||
multiple_orders_by_groups:
|
||||
filename: Current orders sorted by group
|
||||
title: Current orders - by group
|
||||
helpers:
|
||||
current_orders:
|
||||
pay_done: Fully paid
|
||||
pay_none: Nothing to pay
|
||||
pay_amount: To pay %{amount}
|
||||
js:
|
||||
current_orders:
|
||||
articles:
|
||||
above: '%{count} more<br>than available'
|
||||
below: '%{count} left over'
|
||||
equal: all distributed
|
65
plugins/current_orders/config/locales/nl.yml
Normal file
65
plugins/current_orders/config/locales/nl.yml
Normal file
|
@ -0,0 +1,65 @@
|
|||
nl:
|
||||
config:
|
||||
hints:
|
||||
use_current_orders: De current_orders plugin aanzetten. Hiermee kunnen leden met bestelling-toegang bestelaantallen van leden aanpassen in meerdere bestellingen tegelijk. Hiervoor zijn drie nieuwe items in het Bestellingen-menu. Bedoeld voor gebruik op een ophaaldag.
|
||||
keys:
|
||||
use_current_orders: Extra verdeelschermen
|
||||
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}
|
||||
unit: per %{unit}
|
||||
form:
|
||||
article_placeholder: Zoek artikelen...
|
||||
current_orders: Alle huidige bestellingen
|
||||
index:
|
||||
title: Artikelen verdelen
|
||||
ordergroups:
|
||||
piece: st
|
||||
add_new: Huishouden toevoegen...
|
||||
show:
|
||||
title: ! '%{name} verdelen'
|
||||
navigation:
|
||||
receive: Ontvangen
|
||||
articles: Verdelen
|
||||
ordergroups: Ledenbestellingen
|
||||
ordergroups:
|
||||
articles:
|
||||
add_new: Artikel toevoegen...
|
||||
form:
|
||||
ordergroup_placeholder: Kies een huishouden...
|
||||
no_selection: Kies een huishouden om de artikelen te tonen.
|
||||
index:
|
||||
title: Artikelen voor huishouden
|
||||
payment_bar:
|
||||
account_balance: Account balance
|
||||
new_pin: PIN
|
||||
new_transaction: Nieuwe transactie
|
||||
payment: ! 'Betaling:'
|
||||
show:
|
||||
title: Artikelen voor %{name}
|
||||
orders:
|
||||
receive:
|
||||
title: Bestellingen ontvangen
|
||||
no_finished_orders: Er zijn momenteel geen bestellingen die ontvangen hoeven te worden.
|
||||
documents:
|
||||
multiple_orders_by_articles:
|
||||
filename: Huidige bestellingen per artikel
|
||||
title: Huidige bestellingen - per artikel
|
||||
multiple_orders_by_groups:
|
||||
filename: Huidige bestellingen per huishouden
|
||||
title: Huidige bestellingen - per huishouden
|
||||
js:
|
||||
current_orders:
|
||||
articles:
|
||||
above: '%{count} meer dan<br>beschikbaar'
|
||||
below: '%{count} blijft over'
|
||||
equal: alles verdeeld
|
||||
helpers:
|
||||
current_orders:
|
||||
pay_done: Alles betaald
|
||||
pay_none: Niets te betalen
|
||||
pay_amount: Te betalen %{amount}
|
27
plugins/current_orders/config/routes.rb
Normal file
27
plugins/current_orders/config/routes.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
Rails.application.routes.draw do
|
||||
scope '/:foodcoop' do
|
||||
namespace :current_orders do
|
||||
resources :ordergroups, :only => [:index, :show] do
|
||||
collection do
|
||||
get :show_on_group_order_article_create
|
||||
get :show_on_group_order_article_update
|
||||
end
|
||||
end
|
||||
|
||||
resources :articles, :only => [:index, :show] do
|
||||
collection do
|
||||
get :show_on_group_order_article_create
|
||||
end
|
||||
end
|
||||
|
||||
resource :orders, :only => [:show] do
|
||||
collection do
|
||||
get :my
|
||||
get :receive
|
||||
end
|
||||
end
|
||||
|
||||
resources :group_orders, :only => [:index]
|
||||
end
|
||||
end
|
||||
end
|
20
plugins/current_orders/foodsoft_current_orders.gemspec
Normal file
20
plugins/current_orders/foodsoft_current_orders.gemspec
Normal file
|
@ -0,0 +1,20 @@
|
|||
$:.push File.expand_path("../lib", __FILE__)
|
||||
|
||||
# Maintain your gem's version:
|
||||
require "foodsoft_current_orders/version"
|
||||
|
||||
# Describe your gem and declare its dependencies:
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "foodsoft_current_orders"
|
||||
s.version = FoodsoftCurrentOrders::VERSION
|
||||
s.authors = ["wvengen"]
|
||||
s.email = ["dev-voko@willem.engen.nl"]
|
||||
s.homepage = "https://github.com/foodcoop-adam/foodsoft"
|
||||
s.summary = "Quick support for working on all currently active orders in foodsoft."
|
||||
s.description = ""
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
|
||||
|
||||
s.add_dependency "rails"
|
||||
s.add_dependency "deface", "~> 1.0.0"
|
||||
end
|
8
plugins/current_orders/lib/foodsoft_current_orders.rb
Normal file
8
plugins/current_orders/lib/foodsoft_current_orders.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
require "deface"
|
||||
require "foodsoft_current_orders/engine"
|
||||
|
||||
module FoodsoftCurrentOrders
|
||||
def self.enabled?
|
||||
FoodsoftConfig[:use_current_orders]
|
||||
end
|
||||
end
|
15
plugins/current_orders/lib/foodsoft_current_orders/engine.rb
Normal file
15
plugins/current_orders/lib/foodsoft_current_orders/engine.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
module FoodsoftCurrentOrders
|
||||
class Engine < ::Rails::Engine
|
||||
def navigation(primary, context)
|
||||
return unless FoodsoftCurrentOrders.enabled?
|
||||
return if primary[:orders].nil?
|
||||
cond = Proc.new { current_user.role_orders? }
|
||||
[
|
||||
SimpleNavigation::Item.new(primary, :stage_divider, nil, nil, class: 'divider', if: cond),
|
||||
SimpleNavigation::Item.new(primary, :current_orders_receive, I18n.t('current_orders.navigation.receive'), context.receive_current_orders_orders_path, if: cond),
|
||||
SimpleNavigation::Item.new(primary, :current_orders_articles, I18n.t('current_orders.navigation.articles'), context.current_orders_articles_path, if: cond),
|
||||
SimpleNavigation::Item.new(primary, :current_orders_ordergroups, I18n.t('current_orders.navigation.ordergroups'), context.current_orders_ordergroups_path, if: cond)
|
||||
].each {|i| primary[:orders].sub_navigation.items << i }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module FoodsoftCurrentOrders
|
||||
VERSION = "0.0.1"
|
||||
end
|
Loading…
Reference in a new issue