Add optional boxfill phase to orders
This commit is contained in:
parent
c1413ff817
commit
a03789e048
13 changed files with 201 additions and 50 deletions
|
@ -40,7 +40,7 @@ class Admin::ConfigsController < Admin::BaseController
|
|||
# turn recurring rules into something palatable
|
||||
def parse_recurring_selects!(config)
|
||||
if config
|
||||
for k in [:pickup, :ends] do
|
||||
for k in [:pickup, :boxfill, :ends] do
|
||||
if config[k]
|
||||
# allow clearing it using dummy value '{}' ('' would break recurring_select)
|
||||
if config[k][:recurr].present? && config[k][:recurr] != '{}'
|
||||
|
|
|
@ -54,7 +54,8 @@ module Admin::ConfigsHelper
|
|||
checked_value = options.delete(:checked_value) || 'true'
|
||||
unchecked_value = options.delete(:unchecked_value) || 'false'
|
||||
options[:checked] = 'checked' if v=options.delete(:value) && v!='false'
|
||||
form.hidden_field(key, value: unchecked_value, as: :hidden) + form.check_box(key, options, checked_value, false)
|
||||
# different key for hidden field so that allow clocking on label focuses the control
|
||||
form.hidden_field(key, id: "#{key}_", value: unchecked_value, as: :hidden) + form.check_box(key, options, checked_value, false)
|
||||
elsif options[:as] == :select_recurring
|
||||
options[:value] = FoodsoftDateUtil.rule_from(options[:value])
|
||||
options[:rules] ||= []
|
||||
|
@ -111,6 +112,13 @@ module Admin::ConfigsHelper
|
|||
end
|
||||
end
|
||||
|
||||
# @return [String] Tooltip element (span)
|
||||
# @param form [ActionView::Helpers::FormBuilder] Form object.
|
||||
# @param key [Symbol, String] Configuration key of a boolean (e.g. +use_messages+).
|
||||
def config_tooltip(form, key, options={}, &block)
|
||||
content_tag :span, config_input_tooltip_options(form, key, options), &block
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config_input_tooltip_options(form, key, options)
|
||||
|
|
|
@ -28,7 +28,7 @@ class GroupOrder < ActiveRecord::Base
|
|||
data[:order_articles] = {}
|
||||
order.articles_grouped_by_category.each do |article_category, order_articles|
|
||||
order_articles.each do |order_article|
|
||||
|
||||
|
||||
# Get the result of last time ordering, if possible
|
||||
goa = group_order_articles.detect { |goa| goa.order_article_id == order_article.id }
|
||||
|
||||
|
@ -58,8 +58,10 @@ class GroupOrder < ActiveRecord::Base
|
|||
group_order_article = group_order_articles.where(order_article_id: order_article.id).first_or_create
|
||||
|
||||
# Get ordered quantities and update group_order_articles/_quantities...
|
||||
quantities = group_order_articles_attributes.fetch(order_article.id.to_s, {:quantity => 0, :tolerance => 0})
|
||||
group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i)
|
||||
if group_order_articles_attributes
|
||||
quantities = group_order_articles_attributes.fetch(order_article.id.to_s, {:quantity => 0, :tolerance => 0})
|
||||
group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i)
|
||||
end
|
||||
|
||||
# Also update results for the order_article
|
||||
logger.debug "[save_group_order_articles] update order_article.results!"
|
||||
|
@ -86,4 +88,3 @@ class GroupOrder < ActiveRecord::Base
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ class GroupOrderArticle < ActiveRecord::Base
|
|||
group_order.try!(:ordergroup_id)
|
||||
end
|
||||
|
||||
# Updates the quantity/tolerance for this GroupOrderArticle by updating both GroupOrderArticle properties
|
||||
# Updates the quantity/tolerance for this GroupOrderArticle by updating both GroupOrderArticle properties
|
||||
# and the associated GroupOrderArticleQuantities chronologically.
|
||||
#
|
||||
#
|
||||
# See description of the ordering algorithm in the general application documentation for details.
|
||||
def update_quantities(quantity, tolerance)
|
||||
logger.debug("GroupOrderArticle[#{id}].update_quantities(#{quantity}, #{tolerance})")
|
||||
|
@ -104,7 +104,7 @@ class GroupOrderArticle < ActiveRecord::Base
|
|||
|
||||
# Determines how many items of this article the Ordergroup receives.
|
||||
# Returns a hash with three keys: :quantity / :tolerance / :total
|
||||
#
|
||||
#
|
||||
# See description of the ordering algorithm in the general application documentation for details.
|
||||
def calculate_result(total = nil)
|
||||
# return memoized result unless a total is given
|
||||
|
@ -199,5 +199,3 @@ class GroupOrderArticle < ActiveRecord::Base
|
|||
result != result_computed unless result.nil?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class Order < ActiveRecord::Base
|
|||
# Allow separate inputs for date and time
|
||||
# with workaround for https://github.com/einzige/date_time_attribute/issues/14
|
||||
include DateTimeAttributeValidate
|
||||
date_time_attribute :starts, :ends
|
||||
date_time_attribute :starts, :boxfill, :ends
|
||||
|
||||
def stockit?
|
||||
supplier_id == 0
|
||||
|
@ -92,8 +92,16 @@ class Order < ActiveRecord::Base
|
|||
state == "closed"
|
||||
end
|
||||
|
||||
def boxfill?
|
||||
FoodsoftConfig[:use_boxfill] && open? && boxfill.present? && boxfill < Time.now
|
||||
end
|
||||
|
||||
def is_boxfill_useful?
|
||||
FoodsoftConfig[:use_boxfill] && supplier.try(:has_tolerance?)
|
||||
end
|
||||
|
||||
def expired?
|
||||
!ends.nil? && ends < Time.now
|
||||
ends.present? && ends < Time.now
|
||||
end
|
||||
|
||||
# sets up first guess of dates when initializing a new object
|
||||
|
@ -105,7 +113,8 @@ class Order < ActiveRecord::Base
|
|||
last = (DateTime.parse(FoodsoftConfig[:order_schedule][:initial]) rescue nil)
|
||||
last ||= Order.finished.reorder(:starts).first.try(:starts)
|
||||
last ||= self.starts
|
||||
# adjust end date
|
||||
# adjust boxfill and end date
|
||||
self.boxfill ||= FoodsoftDateUtil.next_occurrence last, self.starts, FoodsoftConfig[:order_schedule][:boxfill] if is_boxfill_useful?
|
||||
self.ends ||= FoodsoftDateUtil.next_occurrence last, self.starts, FoodsoftConfig[:order_schedule][:ends]
|
||||
end
|
||||
self
|
||||
|
@ -251,7 +260,9 @@ class Order < ActiveRecord::Base
|
|||
|
||||
def starts_before_ends
|
||||
delta = Rails.env.test? ? 1 : 0 # since Rails 4.2 tests appear to have time differences, with this validation failing
|
||||
errors.add(:ends, I18n.t('orders.model.error_starts_before_ends')) if (ends && starts && ends <= (starts-delta))
|
||||
errors.add(:ends, I18n.t('orders.model.error_starts_before_ends')) if ends && starts && ends <= (starts-delta)
|
||||
errors.add(:ends, I18n.t('orders.model.error_boxfill_before_ends')) if ends && boxfill && ends <= (boxfill-delta)
|
||||
errors.add(:boxfill, I18n.t('orders.model.error_starts_before_boxfill')) if boxfill && starts && boxfill <= (starts-delta)
|
||||
end
|
||||
|
||||
def include_articles
|
||||
|
@ -288,4 +299,3 @@ class Order < ActiveRecord::Base
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ class OrderArticle < ActiveRecord::Base
|
|||
units_to_order
|
||||
end
|
||||
|
||||
# Count quantities of belonging group_orders.
|
||||
# Count quantities of belonging group_orders.
|
||||
# In balancing this can differ from ordered (by supplier) quantity for this article.
|
||||
def group_orders_sum
|
||||
quantity = group_order_articles.collect(&:result).sum
|
||||
|
@ -42,10 +42,11 @@ class OrderArticle < ActiveRecord::Base
|
|||
# Update quantity/tolerance/units_to_order from group_order_articles
|
||||
def update_results!
|
||||
if order.open?
|
||||
quantity = group_order_articles.collect(&:quantity).sum
|
||||
tolerance = group_order_articles.collect(&:tolerance).sum
|
||||
update_attributes(:quantity => quantity, :tolerance => tolerance,
|
||||
:units_to_order => calculate_units_to_order(quantity, tolerance))
|
||||
self.quantity = group_order_articles.collect(&:quantity).sum
|
||||
self.tolerance = group_order_articles.collect(&:tolerance).sum
|
||||
self.units_to_order = calculate_units_to_order(quantity, tolerance)
|
||||
enforce_boxfill if order.boxfill?
|
||||
save!
|
||||
elsif order.finished?
|
||||
update_attribute(:units_to_order, group_order_articles.collect(&:result).sum)
|
||||
end
|
||||
|
@ -186,19 +187,20 @@ class OrderArticle < ActiveRecord::Base
|
|||
|
||||
# @return [Number] Units missing for the last +unit_quantity+ of the article.
|
||||
def missing_units
|
||||
units = price.unit_quantity - ((quantity % price.unit_quantity) + tolerance)
|
||||
units = 0 if units < 0
|
||||
units = 0 if units == price.unit_quantity
|
||||
units
|
||||
_missing_units(price.unit_quantity, quantity, tolerance)
|
||||
end
|
||||
|
||||
|
||||
def missing_units_was
|
||||
_missing_units(price.unit_quantity, quantity_was, tolerance_was)
|
||||
end
|
||||
|
||||
# Check if the result of any associated GroupOrderArticle was overridden manually
|
||||
def result_manually_changed?
|
||||
group_order_articles.any? {|goa| goa.result_manually_changed?}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
def article_and_price_exist
|
||||
errors.add(:article, I18n.t('model.order_article.error_price')) if !(article = Article.find(article_id)) || article.fc_price.nil?
|
||||
rescue
|
||||
|
@ -219,5 +221,26 @@ class OrderArticle < ActiveRecord::Base
|
|||
order.group_orders.each(&:update_price!)
|
||||
end
|
||||
|
||||
end
|
||||
# Throws an exception when the changed article decreases the amount of filled boxes.
|
||||
def enforce_boxfill
|
||||
# Either nothing changes, or
|
||||
# missing_units becomes less and the amount doesn't decrease, or
|
||||
# tolerance was moved to quantity. Only then are changes allowed in the boxfill phase.
|
||||
delta_q = quantity - quantity_was
|
||||
delta_t = tolerance - tolerance_was
|
||||
delta_mis = missing_units - missing_units_was
|
||||
delta_box = units_to_order - units_to_order_was
|
||||
unless (delta_q == 0 && delta_t == 0) ||
|
||||
(delta_mis < 0 && delta_box >= 0 && delta_t >= 0) ||
|
||||
(delta_q > 0 && delta_q == -delta_t)
|
||||
raise ActiveRecord::RecordNotSaved.new("Change not acceptable in boxfill phase, sorry.", self)
|
||||
end
|
||||
end
|
||||
|
||||
def _missing_units(unit_quantity, quantity, tolerance)
|
||||
units = unit_quantity - ((quantity % unit_quantity) + tolerance)
|
||||
units = 0 if units < 0
|
||||
units = 0 if units == unit_quantity
|
||||
units
|
||||
end
|
||||
end
|
||||
|
|
|
@ -116,6 +116,11 @@ class Supplier < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# @return [Boolean] Whether there are articles that would use tolerance (unit_quantity > 1)
|
||||
def has_tolerance?
|
||||
articles.where('articles.unit_quantity > 1').any?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# make sure the shared_sync_method is allowed for the shared supplier
|
||||
|
|
|
@ -11,8 +11,18 @@
|
|||
%span.add-on= t 'number.currency.format.unit'
|
||||
= config_input_field form, :minimum_balance, as: :decimal, class: 'input-small'
|
||||
|
||||
%h4= t '.schedule_title'
|
||||
= form.simple_fields_for :order_schedule do |fields|
|
||||
#boxfill-schedule.collapse{class: ('in' if FoodsoftConfig[:use_boxfill])}
|
||||
= fields.simple_fields_for 'boxfill' do |fields|
|
||||
.fold-line
|
||||
= config_input fields, 'recurr', as: :select_recurring, input_html: {class: 'input-xlarge'}
|
||||
= config_input fields, 'time', input_html: {class: 'input-mini'}
|
||||
= fields.simple_fields_for 'ends' do |fields|
|
||||
.fold-line
|
||||
= config_input fields, 'recurr', as: :select_recurring, input_html: {class: 'input-xlarge'}, allow_blank: true
|
||||
= config_input fields, 'time', input_html: {class: 'input-mini'}
|
||||
-# can't use collapse and tooltip on same element :/
|
||||
= config_input form, :use_boxfill, as: :boolean do
|
||||
= config_tooltip form, :use_boxfill do
|
||||
= config_input_field form, :use_boxfill, as: :boolean, title: '', data: {toggle: 'collapse', target: '#boxfill-schedule'}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
= f.hidden_field :supplier_id
|
||||
.fold-line
|
||||
= f.input :starts, as: :date_picker_time
|
||||
= f.input :boxfill, as: :date_picker_time if @order.is_boxfill_useful?
|
||||
= f.input :ends, as: :date_picker_time
|
||||
= f.input :note, input_html: {rows: 2, class: 'input-xxlarge'}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ en:
|
|||
sent_to_all: Send to all members
|
||||
subject: Subject
|
||||
order:
|
||||
boxfill: Fill boxes after
|
||||
closed_by: Settled by
|
||||
created_by: Created by
|
||||
ends: Ends at
|
||||
|
@ -237,6 +238,8 @@ en:
|
|||
pdf_title: PDF documents
|
||||
tab_messages:
|
||||
emails_title: Sending email
|
||||
tab_payment:
|
||||
schedule_title: Ordering schedule
|
||||
tab_tasks:
|
||||
periodic_title: Periodic tasks
|
||||
tabs:
|
||||
|
@ -478,6 +481,9 @@ en:
|
|||
ends:
|
||||
recurr: Schedule for default order closing date.
|
||||
time: Default time when orders are closed.
|
||||
boxfill:
|
||||
recurr: Schedule for when the box-fill phase starts by default.
|
||||
time: Default time when the box-fill phase of the ordering starts.
|
||||
initial: Schedule starts at this date.
|
||||
page_footer: Shown on each page at the bottom. Enter "blank" to disable the footer completely.
|
||||
pdf_add_page_breaks:
|
||||
|
@ -492,6 +498,7 @@ en:
|
|||
tax_default: Default VAT percentage for new articles.
|
||||
tolerance_is_costly: Order as much of the member tolerance as possible (compared to only as much needed to fill the last box). Enabling this also includes the tolerance in the total price of the open member order.
|
||||
use_apple_points: When the apple point system is enabled, members are required to do some tasks to be able to keep ordering.
|
||||
use_boxfill: When enabled, near end of an order, members are only able to change their order when increases the total amount ordered. This helps to fill any remaining boxes. You still need to set a box-fill date for the orders.
|
||||
use_messages: Allow members to communicate with each other within Foodsoft.
|
||||
use_nick: Show and use nicknames instead of real names. When enabling this, please check that each user has a nickname.
|
||||
use_wiki: Enable editable wiki pages.
|
||||
|
@ -523,6 +530,9 @@ en:
|
|||
ends:
|
||||
recurr: Order ends
|
||||
time: time
|
||||
boxfill:
|
||||
recurr: Box fill after
|
||||
time: time
|
||||
initial: Schedule start
|
||||
page_footer: Page footer
|
||||
pdf_add_page_breaks: Page breaks
|
||||
|
@ -536,6 +546,7 @@ en:
|
|||
time_zone: Time zone
|
||||
tolerance_is_costly: Tolerance is costly
|
||||
use_apple_points: Apple points
|
||||
use_boxfill: Box-fill phase
|
||||
use_messages: Messages
|
||||
use_nick: Use nicknames
|
||||
use_wiki: Enable wiki
|
||||
|
@ -1279,6 +1290,8 @@ en:
|
|||
close_direct_message: Order settled without charging member accounts.
|
||||
error_closed: Order was already settled
|
||||
error_nosel: At least one article must be selected. You may want to delete the order instead?
|
||||
error_boxfill_before_ends: must be after the box-fill date (or remain empty)
|
||||
error_starts_before_boxfill: must be after the start date (or remain empty)
|
||||
error_starts_before_ends: must be after the start date (or remain empty)
|
||||
notice_close: 'Order: %{name}, until %{ends}'
|
||||
stock: Stock
|
||||
|
|
5
db/migrate/20150923190747_add_boxfill_to_order.rb
Normal file
5
db/migrate/20150923190747_add_boxfill_to_order.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddBoxfillToOrder < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :orders, :boxfill, :datetime
|
||||
end
|
||||
end
|
23
db/schema.rb
23
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150301000000) do
|
||||
ActiveRecord::Schema.define(version: 20150923190747) do
|
||||
|
||||
create_table "article_categories", force: :cascade do |t|
|
||||
t.string "name", limit: 255, default: "", null: false
|
||||
|
@ -37,7 +37,7 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
t.integer "article_category_id", limit: 4, default: 0, null: false
|
||||
t.string "unit", limit: 255, default: "", null: false
|
||||
t.string "note", limit: 255
|
||||
t.boolean "availability", limit: 1, default: true, null: false
|
||||
t.boolean "availability", default: true, null: false
|
||||
t.string "manufacturer", limit: 255
|
||||
t.string "origin", limit: 255
|
||||
t.datetime "shared_updated_on"
|
||||
|
@ -61,7 +61,7 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
create_table "assignments", force: :cascade do |t|
|
||||
t.integer "user_id", limit: 4, default: 0, null: false
|
||||
t.integer "task_id", limit: 4, default: 0, null: false
|
||||
t.boolean "accepted", limit: 1, default: false
|
||||
t.boolean "accepted", default: false
|
||||
end
|
||||
|
||||
add_index "assignments", ["user_id", "task_id"], name: "index_assignments_on_user_id_and_task_id", unique: true, using: :btree
|
||||
|
@ -127,18 +127,18 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
t.string "description", limit: 255
|
||||
t.decimal "account_balance", precision: 12, scale: 2, default: 0, null: false
|
||||
t.datetime "created_on", null: false
|
||||
t.boolean "role_admin", limit: 1, default: false, null: false
|
||||
t.boolean "role_suppliers", limit: 1, default: false, null: false
|
||||
t.boolean "role_article_meta", limit: 1, default: false, null: false
|
||||
t.boolean "role_finance", limit: 1, default: false, null: false
|
||||
t.boolean "role_orders", limit: 1, default: false, null: false
|
||||
t.boolean "role_admin", default: false, null: false
|
||||
t.boolean "role_suppliers", default: false, null: false
|
||||
t.boolean "role_article_meta", default: false, null: false
|
||||
t.boolean "role_finance", default: false, null: false
|
||||
t.boolean "role_orders", default: false, null: false
|
||||
t.datetime "deleted_at"
|
||||
t.string "contact_person", limit: 255
|
||||
t.string "contact_phone", limit: 255
|
||||
t.string "contact_address", limit: 255
|
||||
t.text "stats", limit: 65535
|
||||
t.integer "next_weekly_tasks_number", limit: 4, default: 8
|
||||
t.boolean "ignore_apple_restriction", limit: 1, default: false
|
||||
t.boolean "ignore_apple_restriction", default: false
|
||||
end
|
||||
|
||||
add_index "groups", ["name"], name: "index_groups_on_name", unique: true, using: :btree
|
||||
|
@ -184,7 +184,7 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
t.string "subject", limit: 255, null: false
|
||||
t.text "body", limit: 65535
|
||||
t.integer "email_state", limit: 4, default: 0, null: false
|
||||
t.boolean "private", limit: 1, default: false
|
||||
t.boolean "private", default: false
|
||||
t.datetime "created_at"
|
||||
t.integer "reply_to", limit: 4
|
||||
t.integer "group_id", limit: 4
|
||||
|
@ -224,6 +224,7 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
t.integer "updated_by_user_id", limit: 4
|
||||
t.decimal "foodcoop_result", precision: 8, scale: 2
|
||||
t.integer "created_by_user_id", limit: 4
|
||||
t.datetime "boxfill"
|
||||
end
|
||||
|
||||
add_index "orders", ["state"], name: "index_orders_on_state", using: :btree
|
||||
|
@ -316,7 +317,7 @@ ActiveRecord::Schema.define(version: 20150301000000) do
|
|||
t.string "name", limit: 255, default: "", null: false
|
||||
t.string "description", limit: 255
|
||||
t.date "due_date"
|
||||
t.boolean "done", limit: 1, default: false
|
||||
t.boolean "done", default: false
|
||||
t.integer "workgroup_id", limit: 4
|
||||
t.datetime "created_on", null: false
|
||||
t.datetime "updated_on", null: false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe OrderArticle do
|
||||
let(:order) { FactoryGirl.create :order, article_count: 1 }
|
||||
let(:order) { create :order, article_count: 1 }
|
||||
let(:oa) { order.order_articles.first }
|
||||
|
||||
it 'is not ordered by default' do
|
||||
|
@ -19,7 +19,7 @@ describe OrderArticle do
|
|||
|
||||
it 'knows how many items there are' do
|
||||
oa.units_to_order = rand(1..99)
|
||||
expect(oa.units).to eq oa.units_to_order
|
||||
expect(oa.units).to eq oa.units_to_order
|
||||
oa.units_billed = rand(1..99)
|
||||
expect(oa.units).to eq oa.units_billed
|
||||
oa.units_received = rand(1..99)
|
||||
|
@ -34,15 +34,15 @@ describe OrderArticle do
|
|||
end
|
||||
|
||||
describe 'redistribution' do
|
||||
let(:admin) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_finance: true)] }
|
||||
let(:article) { FactoryGirl.create :article, unit_quantity: 3 }
|
||||
let(:order) { FactoryGirl.create :order, article_ids: [article.id] }
|
||||
let(:go1) { FactoryGirl.create :group_order, order: order }
|
||||
let(:go2) { FactoryGirl.create :group_order, order: order }
|
||||
let(:go3) { FactoryGirl.create :group_order, order: order }
|
||||
let(:goa1) { FactoryGirl.create :group_order_article, group_order: go1, order_article: oa }
|
||||
let(:goa2) { FactoryGirl.create :group_order_article, group_order: go2, order_article: oa }
|
||||
let(:goa3) { FactoryGirl.create :group_order_article, group_order: go3, order_article: oa }
|
||||
let(:admin) { create :user, groups:[create(:workgroup, role_finance: true)] }
|
||||
let(:article) { create :article, unit_quantity: 3 }
|
||||
let(:order) { create :order, article_ids: [article.id] }
|
||||
let(:go1) { create :group_order, order: order }
|
||||
let(:go2) { create :group_order, order: order }
|
||||
let(:go3) { create :group_order, order: order }
|
||||
let(:goa1) { create :group_order_article, group_order: go1, order_article: oa }
|
||||
let(:goa2) { create :group_order_article, group_order: go2, order_article: oa }
|
||||
let(:goa3) { create :group_order_article, group_order: go3, order_article: oa }
|
||||
|
||||
# set quantities of group_order_articles
|
||||
def set_quantities(q1, q2, q3)
|
||||
|
@ -117,4 +117,80 @@ describe OrderArticle do
|
|||
|
||||
end
|
||||
|
||||
describe 'boxfill' do
|
||||
before { FoodsoftConfig[:use_boxfill] = true }
|
||||
let(:article) { create :article, unit_quantity: 6 }
|
||||
let(:order) { create :order, article_ids: [article.id], starts: 1.week.ago }
|
||||
let(:oa) { order.order_articles.first }
|
||||
let(:go) { create :group_order, order: order }
|
||||
let(:goa) { create :group_order_article, group_order: go, order_article: oa }
|
||||
|
||||
shared_examples "boxfill" do |success, q|
|
||||
# initial situation
|
||||
before do
|
||||
goa.update_quantities *q.keys[0]
|
||||
oa.update_results!; oa.reload
|
||||
end
|
||||
|
||||
# check starting condition
|
||||
it '(before)' do
|
||||
expect([oa.quantity, oa.tolerance, oa.missing_units]).to eq q.keys[1]
|
||||
end
|
||||
|
||||
# actual test
|
||||
it (success ? 'succeeds' : 'fails') do
|
||||
order.update_attributes(boxfill: boxfill_from)
|
||||
|
||||
r = proc {
|
||||
goa.update_quantities *q.values[0]
|
||||
oa.update_results!
|
||||
}
|
||||
if success
|
||||
r.call
|
||||
else
|
||||
expect(r).to raise_error(ActiveRecord::RecordNotSaved)
|
||||
end
|
||||
|
||||
oa.reload
|
||||
expect([oa.quantity, oa.tolerance, oa.missing_units]).to eq q.values[1]
|
||||
end
|
||||
end
|
||||
|
||||
context 'before the date' do
|
||||
let(:boxfill_from) { 1.hour.from_now }
|
||||
context 'decreasing the missing units' do
|
||||
include_examples "boxfill", true, [6,0]=>[5,0], [6,0,0]=>[5,0,1]
|
||||
end
|
||||
context 'decreasing the tolerance' do
|
||||
include_examples "boxfill", true, [1,2]=>[1,1], [1,2,3]=>[1,1,4]
|
||||
end
|
||||
end
|
||||
|
||||
context 'after the date' do
|
||||
let(:boxfill_from) { 1.second.ago }
|
||||
context 'changing nothing in particular' do
|
||||
include_examples "boxfill", true, [4,1]=>[4,1], [4,1,1]=>[4,1,1]
|
||||
end
|
||||
context 'increasing missing units' do
|
||||
include_examples "boxfill", false, [3,0]=>[2,0], [3,0,3]=>[3,0,3]
|
||||
end
|
||||
context 'increasing tolerance' do
|
||||
include_examples "boxfill", true, [2,1]=>[2,2], [2,1,3]=>[2,2,2]
|
||||
end
|
||||
context 'decreasing quantity to fix missing units' do
|
||||
include_examples "boxfill", true, [7,0]=>[6,0], [7,0,5]=>[6,0,0]
|
||||
end
|
||||
context 'decreasing quantity keeping missing units equal' do
|
||||
include_examples "boxfill", false, [7,0]=>[1,0], [7,0,5]=>[7,0,5]
|
||||
end
|
||||
context 'moving tolerance to quantity' do
|
||||
include_examples "boxfill", true, [4,2]=>[6,0], [4,2,0]=>[6,0,0]
|
||||
end
|
||||
# @todo enable test when tolerance doesn't count in missing_units
|
||||
#context 'decreasing tolerance' do
|
||||
# include_examples "boxfill", false, [0,2]=>[0,0], [0,2,0]=>[0,2,0]
|
||||
#end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue