Skip to content

Commit

Permalink
Merge pull request #100 from foodcoopsat/bugfix/99-enforce-minimum-or…
Browse files Browse the repository at this point in the history
…der-quantity

Fixes #99
  • Loading branch information
yksflip authored Sep 17, 2024
2 parents 99bc201 + d48328f commit 1755d30
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 11 deletions.
26 changes: 15 additions & 11 deletions app/models/article_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,13 @@ class ArticleVersion < ApplicationRecord
validates :price, numericality: { greater_than_or_equal_to: 0 }
validates :group_order_granularity, numericality: { greater_than_or_equal_to: 0 }
validates :deposit, :tax, numericality: true
validates :minimum_order_quantity,
numericality: { allow_nil: true, only_integer: false, if: :supplier_order_unit_is_si_convertible }
validates :minimum_order_quantity,
numericality: { allow_nil: true, only_integer: true, unless: :supplier_order_unit_is_si_convertible }
validates :minimum_order_quantity, numericality: { allow_nil: true }

# validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type], if: Proc.new {|a| a.supplier.shared_sync_method.blank? or a.supplier.shared_sync_method == 'import' }
# validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type, :unit, :unit_quantity]
validate :uniqueness_of_name
validate :only_one_unit_type
validate :minimum_order_quantity_as_integer, unless: :supplier_order_unit_is_si_convertible

# Replace numeric seperator with database format
localize_input_of :price, :tax, :deposit
Expand Down Expand Up @@ -117,13 +116,7 @@ def minimum_order_quantity=(value)
if value.blank?
self[:minimum_order_quantity] = nil
else
value = value.gsub(I18n.t('number.format.separator'), '.') if value.is_a?(String)
begin
value = value.to_i if Float(value) % 1 == 0
rescue ArgumentError
# not any number -> let validation handle this
end
super(value)
super
end
end

Expand Down Expand Up @@ -190,6 +183,17 @@ def uniqueness_of_name
end
end

def minimum_order_quantity_as_integer
begin
return if Float(minimum_order_quantity) % 1 == 0
rescue ArgumentError, TypeError
# not any number -> let numericality validation handle this
return
end

errors.add(:minimum_order_quantity, :only_integer)
end

def only_one_unit_type
return if unit.blank? || supplier_order_unit.blank?

Expand Down
1 change: 1 addition & 0 deletions app/models/order_article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def update_results!
# 4 | 5 | 4 | 2
#
def calculate_units_to_order(quantity, tolerance = 0)
return 0 if !price.minimum_order_quantity.nil? && quantity + tolerance < price.minimum_order_quantity
return price.minimum_order_quantity if quantity > 0 && !price.minimum_order_quantity.nil? && quantity < price.minimum_order_quantity && quantity + tolerance >= price.minimum_order_quantity

unit_size = price.convert_quantity(1, price.supplier_order_unit, price.group_order_unit)
Expand Down
2 changes: 2 additions & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ de:
name:
taken: Name ist bereits vergeben
taken_with_unit: Name und Einheit sind bereits vergeben
minimum_order_quantity:
only_integer: Muss eine Ganzzahl sein, wenn die Liefereinheit eine Stückeinheit ist.
supplier:
attributes:
shared_sync_method:
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ en:
name:
taken: name is already taken
taken_with_unit: name and unit are already taken
minimum_order_quantity:
only_integer: Must be an integer if supplier order unit is a piece unit
supplier:
attributes:
shared_sync_method:
Expand Down
2 changes: 2 additions & 0 deletions spec/factories/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
order_number { nil }
unit_quantity { nil }
unit { nil }
minimum_order_quantity { nil }
supplier_order_unit { 'XPK' }
group_order_unit { 'XPK' }
billing_unit { 'XPK' }
Expand All @@ -23,6 +24,7 @@
order_number: evaluator.order_number,
unit_quantity: evaluator.unit_quantity,
unit: evaluator.unit,
minimum_order_quantity: evaluator.minimum_order_quantity,
supplier_order_unit: evaluator.supplier_order_unit,
group_order_unit: evaluator.group_order_unit,
billing_unit: evaluator.billing_unit,
Expand Down
55 changes: 55 additions & 0 deletions spec/models/order_article_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,59 @@ def goa_reload
# end
end
end

describe 'minimum order quantity' do
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_context 'minimum order quantity' do |quantity|
before do
goa.update_quantities(quantity[:quantity], quantity[:tolerance])
oa.update_results!
oa.reload
end

it 'is calculated correctly' do
expect(oa.units_to_order).to eq quantity[:expected_units_to_order]
end
end

context 'without unit_quantity' do
let(:article) { create(:article, minimum_order_quantity: 10) }

context 'doesn\'t order anything, if the minimum order quantity hasn\'t been reached' do
include_examples 'minimum order quantity', { quantity: 4, tolerance: 0, expected_units_to_order: 0 }
end

context 'orders the minimum order quantity, if tolerance allows for it' do
include_examples 'minimum order quantity', { quantity: 9, tolerance: 1, expected_units_to_order: 10 }
end

context 'orders the desired amount, if minimum order quantity has been surpassed' do
include_examples 'minimum order quantity', { quantity: 12, tolerance: 1, expected_units_to_order: 12 }
end
end

context 'with unit_quantity' do
let(:article) { create(:article, minimum_order_quantity: 2, unit_quantity: 5) }

context 'doesn\'t order anything if the minimum order quantity hasn\'t been reached' do
include_examples 'minimum order quantity', { quantity: 4, tolerance: 0, expected_units_to_order: 0 }
end

context 'orders the minimum order quantity if tolerance allows for it' do
include_examples 'minimum order quantity', { quantity: 9, tolerance: 1, expected_units_to_order: 2 }
end

context 'orders a lower amount, even if minimum order quantity has been surpassed, but unit_quantity demands it' do
include_examples 'minimum order quantity', { quantity: 12, tolerance: 1, expected_units_to_order: 2 }
end

context 'orders the exact amount, if minimum order quantity has been surpassed and unit_quantity allows for it' do
include_examples 'minimum order quantity', { quantity: 14, tolerance: 1, expected_units_to_order: 3 }
end
end
end
end

0 comments on commit 1755d30

Please sign in to comment.