Skip to content

Commit

Permalink
wip: feat: add a maximum order quantity for articles
Browse files Browse the repository at this point in the history
  • Loading branch information
yksflip committed Aug 29, 2024
1 parent 99bc201 commit 9cd0d22
Show file tree
Hide file tree
Showing 18 changed files with 138 additions and 10 deletions.
1 change: 1 addition & 0 deletions app/assets/javascripts/article-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ArticleForm {
this.supplierUnitSelect$ = $(`#${this.unitFieldsIdPrefix}_supplier_order_unit`, this.articleForm$);
this.unitRatiosTable$ = $('#fc_base_price', this.articleForm$);
this.minimumOrderQuantity$ = $(`#${this.unitFieldsIdPrefix}_minimum_order_quantity`, this.articleForm$);
this.maximumOrderQuantity$ = $(`#${this.unitFieldsIdPrefix}_maximum_order_quantity`, this.articleForm$);
this.billingUnit$ = $(`#${this.unitFieldsIdPrefix}_billing_unit`, this.articleForm$);
this.groupOrderGranularity$ = $(`#${this.unitFieldsIdPrefix}_group_order_granularity`, this.articleForm$);
this.groupOrderUnit$ = $(`#${this.unitFieldsIdPrefix}_group_order_unit`, this.articleForm$);
Expand Down
17 changes: 11 additions & 6 deletions app/assets/javascripts/group-order-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class GroupOrderForm {
row$.find('.btn-ordering.increase').click((event) => this.increaseOrDecrease($(event.target).parents('.btn-group').find('input.numeric'), true));

quantityAndTolerance$.change(() => {
const maximumOrderQuantity = parseFloat(quantity$.data('maximum-order-quantity'));
if (maximumOrderQuantity) {
quantity$.val(Math.min(parseFloat(quantity$.val()), maximumOrderQuantity));
}
this.updateMissingUnits(row$, quantity$);
this.updateBalance();
});
Expand All @@ -59,8 +63,8 @@ class GroupOrderForm {
// determine bgcolor and submit button state according to balance
var bgcolor = '';
if (balance < this.minimumBalance) {
bgcolor = '#FF0000';
this.submitButton$.attr('disabled', 'disabled')
bgcolor = '#FF0000';
this.submitButton$.attr('disabled', 'disabled')
} else {
this.submitButton$.removeAttr('disabled')
}
Expand Down Expand Up @@ -96,7 +100,7 @@ class GroupOrderForm {
value = Math.max(parseFloat(min), value);
}

const max = field$.attr('max');
const max = field$.attr('max') || field$.data('maximum-order-quantity');
if (max !== undefined) {
value = Math.min(parseFloat(max), value);
}
Expand All @@ -119,8 +123,8 @@ class GroupOrderForm {
const totalPrice$ = row$.find('*[id^="price_"][id$="_display"]');

const missing$ = row$.find('.missing-units');

let quantity = parseFloat(quantity$.val().trim().replace(',', '.'));
const maximumOrderQuantity = parseFloat(quantity$.data('maximum-order-quantity'));
let quantity = Math.min(maximumOrderQuantity, parseFloat(quantity$.val().trim().replace(',', '.')));
if (isNaN(quantity)) {
quantity = 0;
}
Expand All @@ -138,12 +142,13 @@ class GroupOrderForm {
const othersTolerance = parseFloat(quantity$.data('others-tolerance'));
const usedQuantity = parseFloat(quantity$.data('used-quantity'));
const minimumOrderQuantity = parseFloat(quantity$.data('minimum-order-quantity'));

const price = parseFloat(quantity$.data('price'));

const totalQuantity = Big(quantity).add(othersQuantity).toNumber();
const totalTolerance = Big(tolerance).add(othersTolerance).toNumber();

const totalPacks = this.calculatePacks(packSize, totalQuantity, totalTolerance, minimumOrderQuantity)
const totalPacks = this.calculatePacks(packSize, totalQuantity, totalTolerance, minimumOrderQuantity);

const totalPrice = Big(price).mul(Big(quantity).add(this.toleranceIsCostly ? tolerance : 0)).toNumber();

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/order_articles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def create

def update
# begin
version_params = params.require(:article_version).permit(:id, :unit, :supplier_order_unit, :minimum_order_quantity,
version_params = params.require(:article_version).permit(:id, :unit, :supplier_order_unit, :minimum_order_quantity, :maximum_order_quantity,
:billing_unit, :group_order_granularity, :group_order_unit, :price, :price_unit, :tax, :deposit, article_unit_ratios_attributes: %i[id sort quantity unit _destroy])
@order_article.update_handling_versioning!(params[:order_article], version_params)
# TODO-article-version
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/group_orders_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module GroupOrdersHelper
def data_to_js(ordering_data)
ordering_data[:order_articles].map do |id, data|
[id, data[:price], data[:unit], data[:total_price], data[:others_quantity], data[:others_tolerance],
data[:used_quantity], data[:quantity_available]]
data[:used_quantity], data[:quantity_available], data[:maximum_order_quantity]]
end.map do |row|
"addData(#{row.join(', ')});"
end.join("\n")
Expand Down
1 change: 1 addition & 0 deletions app/models/article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def unequal_attributes(new_article, options = {})
unit: [latest_article_version.unit, new_unit],
supplier_order_unit: [latest_article_version.supplier_order_unit, new_article.supplier_order_unit],
minimum_order_quantity: [latest_article_version.minimum_order_quantity, new_article.minimum_order_quantity],
maximum_order_quantity: [latest_article_version.maximum_order_quantity, new_article.maximum_order_quantity],
billing_unit: [latest_article_version.billing_unit || latest_article_version.supplier_order_unit,
new_article.billing_unit || new_article.supplier_order_unit],
group_order_granularity: [latest_article_version.group_order_granularity, new_article.group_order_granularity],
Expand Down
18 changes: 18 additions & 0 deletions app/models/article_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class ArticleVersion < ApplicationRecord
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 :maximum_order_quantity,
numericality: { allow_nil: true, only_integer: false, if: :supplier_order_unit_is_si_convertible }
validates :maximum_order_quantity,
numericality: { allow_nil: true, only_integer: true, unless: :supplier_order_unit_is_si_convertible }
# 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
Expand Down Expand Up @@ -127,6 +131,20 @@ def minimum_order_quantity=(value)
end
end

def maximum_order_quantity=(value)
if value.blank?
self[:maximum_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)
end
end

def self_or_ratios_changed?
changed? || @article_unit_ratios_changed || article_unit_ratios.any?(&:changed?)
end
Expand Down
5 changes: 5 additions & 0 deletions app/models/group_order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ def load_data
order_article.article_version.convert_quantity(
order_article.article_version.minimum_order_quantity, order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit
)
end,
maximum_order_quantity: if order_article.article_version.maximum_order_quantity
order_article.article_version.convert_quantity(
order_article.article_version.maximum_order_quantity, order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit
)
end
}
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/order_article.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def update_results!
# 4 | 5 | 4 | 2
#
def calculate_units_to_order(quantity, tolerance = 0)
quantity = [price.maximum_order_quantity || quantity, quantity].min
return 0 if price.minimum_order_quantity && quantity < 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
4 changes: 4 additions & 0 deletions app/views/articles/_edit_all_table.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
= form.input :minimum_order_quantity, label: "Mininum order quantity" do
.input-append
= form.input_field :minimum_order_quantity, class: 'input-mini', title: "total minimum order quantity for this article"
.fold-line
= form.input :maximum_order_quantity, label: "Mininum order quantity" do
.input-append
= form.input_field :maximum_order_quantity, class: 'input-mini', title: "total minimum order quantity for this article"
.fold-line
= form.input :billing_unit, as: :select, collection: [], input_html: {'data-initial-value': article.billing_unit, class: 'input-medium'}, include_blank: false
.fold-line
Expand Down
7 changes: 7 additions & 0 deletions app/views/articles/_sync_table.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@
%span.add-on
- unless changed_article.new_record?
%p.help-block{style: 'color: grey;'}=article.minimum_order_quantity.to_s
.fold-line
= form.input :maximum_order_quantity, label: "Maximum order quantity" do
.input-append
= form.input_field :maximum_order_quantity, class: 'input-mini', style: highlight_new(attrs, :maximum_order_quantity), title: "total maximum order quantity for this article"
%span.add-on
- unless changed_article.new_record?
%p.help-block{style: 'color: grey;'}=article.maximum_order_quantity.to_s
.fold-line
= form.input :billing_unit, hint: changed_article.new_record? ? nil : ArticleUnitsLib.get_translated_name_for_code(article.billing_unit || article.supplier_order_unit), hint_html: {style: 'color: grey;'}, as: :select, collection: [], input_html: {'data-initial-value': changed_article.billing_unit, class: 'input-medium', style: highlight_new(attrs, :billing_unit)}, include_blank: false
.fold-line
Expand Down
1 change: 1 addition & 0 deletions app/views/articles/upload.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
%th= Article.human_attribute_name(:custom_unit)
%th= Article.human_attribute_name(:ratios_to_supplier_order_unit)
%th= Article.human_attribute_name(:minimum_order_quantity)
%th= Article.human_attribute_name(:maximum_order_quantity)
%th= Article.human_attribute_name(:billing_unit)
%th= Article.human_attribute_name(:group_order_granularity)
%th= Article.human_attribute_name(:group_order_unit)
Expand Down
1 change: 1 addition & 0 deletions app/views/group_orders/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
- quantity_data['used_quantity'] = @ordering_data[:order_articles][order_article.id][:used_quantity]
- quantity_data['price'] = @ordering_data[:order_articles][order_article.id][:price]
- quantity_data['minimum_order_quantity'] = @ordering_data[:order_articles][order_article.id][:minimum_order_quantity] unless @ordering_data[:order_articles][order_article.id][:minimum_order_quantity].nil?
- quantity_data['maximum_order_quantity'] = @ordering_data[:order_articles][order_article.id][:maximum_order_quantity] unless @ordering_data[:order_articles][order_article.id][:maximum_order_quantity].nil?
- quantity_data['e2e-order-article-id'] = order_article.id
%td.used-unused
%span.used= number_with_precision(@ordering_data[:order_articles][order_article.id][:used_quantity], precision: 3, strip_insignificant_zeros: true)
Expand Down
5 changes: 5 additions & 0 deletions app/views/shared/_article_fields_units.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
.input-append
= f.input_field :minimum_order_quantity, class: 'input-mini'
%span.add-on
.fold-line
= f.input :maximum_order_quantity do
.input-append
= f.input_field :maximum_order_quantity, class: 'input-mini'
%span.add-on
.fold-line
= f.input :billing_unit, as: :select, collection: [], input_html: {'data-initial-value': article.billing_unit, class: 'input-medium'}, include_blank: false
.fold-line
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddMaximumOrderQuantityToArticleVersions < ActiveRecord::Migration[7.0]
def change
add_column :article_versions, :maximum_order_quantity, :float
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2024_07_26_083744) do
ActiveRecord::Schema[7.0].define(version: 2024_08_29_112007) do
create_table "action_text_rich_texts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.string "name", null: false
t.text "body", size: :long
Expand Down Expand Up @@ -92,6 +92,7 @@
t.string "group_order_unit"
t.decimal "group_order_granularity", precision: 8, scale: 3, default: "1.0", null: false
t.float "minimum_order_quantity"
t.float "maximum_order_quantity"
t.index ["article_category_id"], name: "index_article_versions_on_article_category_id"
t.index ["article_id", "created_at"], name: "index_article_versions_on_article_id_and_created_at", unique: true
end
Expand Down
13 changes: 13 additions & 0 deletions spec/models/article_version_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@
let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) }
let(:goa) { create(:group_order_article, group_order: go, order_article: order.order_articles.first) }

describe 'when maximum_order_quantity is set' do
it 'validates that the quantity is not greater than the maximum_order_quantity' do
article_version = order.order_articles.first.article_version
article_version.maximum_order_quantity = 5
article_version.save

order.order_articles.first.quantity = 6
order.save

expect(order.errors[:base]).to include('Order quantity exceeds maximum order quantity')
end
end

describe 'versioning depending on order status' do
let(:article_version) { order.order_articles.first.article_version }
let(:article) { article_version.article }
Expand Down
60 changes: 60 additions & 0 deletions spec/models/order_article_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,64 @@ def goa_reload
# end
end
end

describe 'calculate_units_to_order with si unit_quantity' do
let(:article) { create(:article, unit_quantity: 3) }
let(:order) { create(:order, article_ids: [article.id]) }
let(:oa) { order.order_articles.first }

it 'simple case' do
expect(oa.calculate_units_to_order(6)).to eq 2
end

it 'with tolerance' do
expect(oa.calculate_units_to_order(5, 0)).to eq 1
expect(oa.calculate_units_to_order(5, 1)).to eq 2
end

it 'minimum order quantity' do
oa.article_version.update_attribute :minimum_order_quantity, 6
expect(oa.calculate_units_to_order(3)).to eq 0
expect(oa.calculate_units_to_order(6)).to eq 2
end

it 'maximum order quantity' do
oa.article_version.update_attribute :maximum_order_quantity, 6
expect(oa.calculate_units_to_order(9)).to eq 2
end
end

describe 'calculate_units_to_order with article_version' do
let(:article_version) { create(:article_version, article_unit_ratios: [create(:article_unit_ratio, quantity: 3)]) }
let(:article) { article_version.article }
let(:order) { create(:order, article_ids: [article.id]) }
let(:oa) { order.order_articles.first }

it 'simple case' do
expect(oa.calculate_units_to_order(3)).to eq 1
end

it 'with tolerance' do
expect(oa.calculate_units_to_order(5, 0)).to eq 1
expect(oa.calculate_units_to_order(5, 1)).to eq 2
end

it 'minimum order quantity' do
oa.article_version.update_attribute :minimum_order_quantity, 6
expect(oa.calculate_units_to_order(3)).to eq 0
expect(oa.calculate_units_to_order(6)).to eq 2
end

it 'maximum order quantity' do
oa.article_version.update_attribute :maximum_order_quantity, 6
expect(oa.calculate_units_to_order(9)).to eq 2
end

it 'maximum and minimum' do
oa.article_version.update_attribute :maximum_order_quantity, 9
oa.article_version.update_attribute :minimum_order_quantity, 6
expect(oa.calculate_units_to_order(12)).to eq 3
expect(oa.calculate_units_to_order(3)).to eq 0
end
end
end
1 change: 0 additions & 1 deletion tmp/.gitignore

This file was deleted.

0 comments on commit 9cd0d22

Please sign in to comment.