Skip to content

Commit

Permalink
First draft of #31
Browse files Browse the repository at this point in the history
  • Loading branch information
lentschi committed Feb 2, 2024
1 parent 88b7528 commit 683d2af
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 39 deletions.
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//= require i18n/translations
//= require_self
//= require units-converter
//= require migrate-units-form
//= require article-form
//= require unit-conversion-field
//= require group-order-form
Expand Down
142 changes: 142 additions & 0 deletions app/assets/javascripts/migrate-units-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
class MigrateUnitsForm {
constructor(articleUnitRatioTemplate$, table$, units) {
this.articleUnitRatioTemplate$ = articleUnitRatioTemplate$;
this.table$ = table$;
this.units = units;

this.initializeUnitSelects();
this.initializeArticlesList();
}

loadAvailableUnits() {
this.availableUnits = Object.entries(this.units)
.filter(([, unit]) => unit.visible)
.map(([code, unit]) => ({ key: code, label: unit.name, baseUnit: unit.baseUnit, symbol: unit.symbol, aliases: unit.aliases ? unit.aliases : [] }));
}

initializeUnitSelects() {
this.loadAvailableUnits();
this.table$.find('select[name^="samples["]').select2();
const form = this;
this.table$.find('select[name^="samples["][name$="[supplier_order_unit]"]').each(function() {
form.updateUnitsInSelect(form.availableUnits, $(this));
form.updateFirstUnitRatioSelect($(this).parents('tr'));
form.updateGroupOrderUnitSelect($(this).parents('tr'));
form.updateFirstUnitRatioQuantity($(this).parents('tr'));
});
this.table$.find('select[name^="samples["][name$="[supplier_order_unit]"]').change(function() {
form.updateFirstUnitRatioSelect($(this).parents('tr'));
form.updateGroupOrderUnitSelect($(this).parents('tr'));
form.updateFirstUnitRatioQuantity($(this).parents('tr'));
});
this.table$.find('select[name^="samples["][name$="[first_ratio_unit]"]').change(function() {
form.updateGroupOrderUnitSelect($(this).parents('tr'));
form.updateFirstUnitRatioQuantity($(this).parents('tr'));
});
}

updateFirstUnitRatioQuantity(row$) {
const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]');
const firstRatioQuantity$ = row$.find('input[name$="[first_ratio_quantity]"]');
if (firstRatioSelect$.val() === '') {
firstRatioQuantity$.val('');
firstRatioQuantity$.attr('disabled', 'disabled');
} else {
firstRatioQuantity$.removeAttr('disabled');
}
}

updateGroupOrderUnitSelect(row$) {
const supplierUnitSelect$ = row$.find('select[name$="[supplier_order_unit]"]');
const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]');
const groupOrderUnit$ = row$.find('select[name$="[group_order_unit]"]');

const unitsSelectedAbove = [];
const chosenSupplierUnitOption$ = supplierUnitSelect$.find(`option[value="${supplierUnitSelect$.val()}"]`);
unitsSelectedAbove.push({ key: chosenSupplierUnitOption$.val(), label: chosenSupplierUnitOption$.text() });

if (firstRatioSelect$.val() != '') {
const chosenFirstRatioOption$ = firstRatioSelect$.find(`option[value="${firstRatioSelect$.val()}"]`);
unitsSelectedAbove.push({ key: chosenFirstRatioOption$.val(), label: chosenFirstRatioOption$.text() });
}

const availableUnits = [];
for (const unitSelectedAbove of unitsSelectedAbove) {
availableUnits.push(unitSelectedAbove, ...this.availableUnits.filter(availableUnit => {
if (availableUnit.key === unitSelectedAbove.key) {
return false;
}

const otherUnit = this.availableUnits.find(unit => unit.key === unitSelectedAbove.key);
return otherUnit !== undefined && otherUnit.baseUnit !== null && availableUnit.baseUnit === otherUnit.baseUnit;
}));
}

this.updateUnitsInSelect(availableUnits, groupOrderUnit$);
}

updateFirstUnitRatioSelect(row$) {
const supplierUnitSelect$ = row$.find('select[name$="[supplier_order_unit]"]');
const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]');
const isUnitOrBaseUnitSelected = (unit, select$) => {
const code = select$.val();
const selectedUnit = this.units[code];
return unit.key !== code && (!unit.baseUnit || !selectedUnit || !selectedUnit.baseUnit || unit.baseUnit !== selectedUnit.baseUnit);
};

const remainingAvailableUnits = this.availableUnits.filter(unit => isUnitOrBaseUnitSelected(unit, supplierUnitSelect$));
this.updateUnitsInSelect(remainingAvailableUnits, firstRatioSelect$, true);
}

initializeArticlesList() {
this.table$.find('.articles-list .expander').click(function () {
const currentList$ = $(this).parents('.articles-list');
currentList$.find('.expander').addClass('d-none');
currentList$.find('.collapser').removeClass('d-none');
currentList$.find('.list').removeClass('d-none');
});

this.table$.find('.articles-list .collapser').click(function () {
const currentList$ = $(this).parents('.articles-list');
currentList$.find('.expander').removeClass('d-none');
currentList$.find('.collapser').addClass('d-none');
currentList$.find('.list').addClass('d-none');
});
}

updateUnitsInSelect(units, unitSelect$, includeBlank) {
const valueBeforeUpdate = unitSelect$.val();

unitSelect$.empty();
if (includeBlank) {
unitSelect$.append($(`<option value=""></option>`));
}
for (const unit of units) {
unitSelect$.append($(`<option value="${unit.key}">${unit.label}</option>`));
}

const initialValue = unitSelect$.attr('data-initial-value');
if (initialValue) {
unitSelect$.val(initialValue);
unitSelect$.removeAttr('data-initial-value');
} else {
if (unitSelect$.find(`option[value="${valueBeforeUpdate}"]`).length > 0) {
unitSelect$.val(valueBeforeUpdate);
} else {
unitSelect$.val(unitSelect$.find('option:first').val());
}
}

unitSelect$.trigger('change');

unitSelect$.parents('.control-group').find('.immutable_unit_label').remove();
if (units.length === 1) {
unitSelect$.parents('.controls').hide();
unitSelect$.parents('.control-group').append($(`<div class="immutable_unit_label control-label">${units[0].label}</div>`))
} else {
unitSelect$.parents('.controls').show();
}
}


}
4 changes: 4 additions & 0 deletions app/assets/stylesheets/bootstrap_and_overrides.css.less
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,10 @@ span.negative_amout {
display: flex;
}

.d-none {
display: none;
}

.align-items-center {
align-items: center;
}
Expand Down
188 changes: 150 additions & 38 deletions app/controllers/articles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ def create

# Updates one Article and highlights the line if succeded
def update
if @article.update_attributes(latest_article_version_attributes: params[:article_version])
render :layout => false
else
Rails.logger.info @article.errors.to_yaml.to_s
render :action => 'new', :layout => false
Article.transaction do
if @article.update_attributes(latest_article_version_attributes: params[:article_version])
render :layout => false
else
Rails.logger.info @article.errors.to_yaml.to_s
render :action => 'new', :layout => false
end
end
end

Expand All @@ -98,48 +100,123 @@ def edit_all
end

def migrate_units
@articles = @supplier.articles.with_latest_versions_and_categories.undeleted.includes(latest_article_version: [:article_unit_ratios])
@original_units = {}
@articles.each do |article|
article_version = article.latest_article_version
quantity = 1
ratios = article_version.article_unit_ratios
build_article_migration_samples
end

@original_units[article.id] = article_version.unit
def complete_units_migration
@invalid_articles = []
@samples = []

next if ratios.length > 1
Article.transaction do
params[:samples].values.each do |sample|

Check failure on line 111 in app/controllers/articles_controller.rb

View workflow job for this annotation

GitHub Actions / test

Style/HashEachMethods: Use `each_value` instead of `values.each`.
next unless sample[:apply_migration] == "1"

original_unit = nil
articles = Article.with_latest_versions_and_categories
.includes(latest_article_version: [:article_unit_ratios])
.find(sample[:article_ids])
articles.each do |article|
latest_article_version = article.latest_article_version
original_unit = latest_article_version.unit
next if latest_article_version.article_unit_ratios.length > 1 ||
latest_article_version.billing_unit != latest_article_version.group_order_unit ||
latest_article_version.price_unit != latest_article_version.group_order_unit

article_version_params = sample.slice(:supplier_order_unit, :group_order_granularity, :group_order_unit)
article_version_params[:unit] = nil
article_version_params[:billing_unit] = article_version_params[:group_order_unit]
article_version_params[:price_unit] = article_version_params[:group_order_unit]
article_version_params[:article_unit_ratios_attributes] = {}
unless sample[:first_ratio_unit].blank?
article_version_params[:article_unit_ratios_attributes]["1"] = {
id: latest_article_version.article_unit_ratios.first&.id,
sort: 1,
quantity: sample[:first_ratio_quantity],
unit: sample[:first_ratio_unit]
}
end
article_version_params[:id] = latest_article_version.id
unless article.update_attributes(latest_article_version_attributes: article_version_params)
@invalid_articles << article
end
end

if ratios.length == 1 && ratios[0].quantity != 1 && ratios[0].unit == 'XPP'
quantity = ratios[0].quantity
errors = articles.find { |a| !a.errors.nil? }&.errors
@samples << {
unit: original_unit,
conversion_result: sample
.except(:article_ids, :first_ratio_quantity, :first_ratio_unit)
.merge(
first_ratio: {
quantity: sample[:first_ratio_quantity],
unit: sample[:first_ratio_unit]
}
),
articles: articles,
errors: errors,
error: !errors.blank?
}
end
@supplier.update_attribute(:unit_migration_completed, Time.now)
raise ActiveRecord::Rollback unless @invalid_articles.empty?
end

conversion_result = ArticleUnitsLib.convert_old_unit(article_version.unit, quantity)
if @invalid_articles.empty?
redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.complete_units_migration.notice')
else
additional_units = @samples.map do |sample|
[sample[:conversion_result][:supplier_order_unit], sample[:conversion_result][:group_order_unit], sample[:conversion_result][:first_ratio]&.dig(:unit)]
end.flatten.uniq.compact
load_article_units(additional_units)

next if conversion_result.nil? ||
(conversion_result[:first_ratio].nil? && !article_version.article_unit_ratios.empty?) ||
(!conversion_result[:first_ratio].nil? && article_version.article_unit_ratios.length > 1)
flash.now.alert = I18n.t('articles.controller.error_invalid')
render :migrate_units
end
end

article_version.unit = nil
article_version.supplier_order_unit = conversion_result[:supplier_order_unit]
article_version.group_order_granularity = conversion_result[:group_order_granularity]
article_version.group_order_unit = conversion_result[:group_order_unit]
# def migrate_units
# @articles = @supplier.articles.with_latest_versions_and_categories.undeleted.includes(latest_article_version: [:article_unit_ratios])
# @original_units = {}
# @articles.each do |article|
# article_version = article.latest_article_version
# quantity = 1
# ratios = article_version.article_unit_ratios

first_ratio = conversion_result[:first_ratio]
next if first_ratio.nil?
# @original_units[article.id] = article_version.unit

first_ratio = first_ratio.merge(sort: 1)
first_existing_ratio = article_version.article_unit_ratios[0]
if first_existing_ratio.nil?
article_version.article_unit_ratios.build(first_ratio)
else
first_existing_ratio.assign_attributes(first_ratio)
end
end
# next if ratios.length > 1

load_article_units
# if ratios.length == 1 && ratios[0].quantity != 1 && ratios[0].unit == 'XPP'
# quantity = ratios[0].quantity
# end

render :edit_all
end
# conversion_result = ArticleUnitsLib.convert_old_unit(article_version.unit, quantity)

# next if conversion_result.nil? ||
# (conversion_result[:first_ratio].nil? && !article_version.article_unit_ratios.empty?) ||
# (!conversion_result[:first_ratio].nil? && article_version.article_unit_ratios.length > 1)

# article_version.unit = nil
# article_version.supplier_order_unit = conversion_result[:supplier_order_unit]
# article_version.group_order_granularity = conversion_result[:group_order_granularity]
# article_version.group_order_unit = conversion_result[:group_order_unit]

# first_ratio = conversion_result[:first_ratio]
# next if first_ratio.nil?

# first_ratio = first_ratio.merge(sort: 1)
# first_existing_ratio = article_version.article_unit_ratios[0]
# if first_existing_ratio.nil?
# article_version.article_unit_ratios.build(first_ratio)
# else
# first_existing_ratio.assign_attributes(first_ratio)
# end
# end

# load_article_units

# render :edit_all
# end

# Updates all article of specific supplier
def update_all
Expand Down Expand Up @@ -293,22 +370,57 @@ def update_synchronized

private

def build_article_migration_samples
articles = @supplier.articles.with_latest_versions_and_categories.undeleted.includes(latest_article_version: [:article_unit_ratios])
samples_hash = {}
articles.each do |article|
article_version = article.latest_article_version
quantity = 1
ratios = article_version.article_unit_ratios

next if ratios.length > 1 ||
article_version.billing_unit != article_version.group_order_unit ||
article_version.price_unit != article_version.group_order_unit

if ratios.length == 1 && ratios[0].quantity != 1 && ratios[0].unit == 'XPP'
quantity = ratios[0].quantity
end

samples_hash[article_version.unit] = {} if samples_hash[article_version.unit].nil?
samples_hash[article_version.unit][quantity] = [] if samples_hash[article_version.unit][quantity].nil?
samples_hash[article_version.unit][quantity] << article
end
@samples = samples_hash.map do |unit, quantities_hash|
quantities_hash.map do |quantity, sample_articles|
conversion_result = ArticleUnitsLib.convert_old_unit(unit, quantity)
{ unit: unit, quantity: quantity, articles: sample_articles, conversion_result: conversion_result }
end
end
@samples = @samples.flatten
.reject { |sample| sample[:conversion_result].nil? }

additional_units = @samples.map do |sample|
[sample[:conversion_result][:supplier_order_unit], sample[:conversion_result][:group_order_unit], sample[:conversion_result][:first_ratio]&.dig(:unit)]
end.flatten.uniq.compact
load_article_units(additional_units)
end

def load_article
@article = Article
.with_latest_versions_and_categories
.includes(latest_article_version: [:article_unit_ratios])
.find(params[:id])
end

def load_article_units
def load_article_units(additional_units = [])
additional_units = if !@article.nil?
@article.current_article_units
elsif !@articles.nil?
@articles.map(&:current_article_units)
.flatten
.uniq
else
[]
additional_units
end

@article_units = ArticleUnit.as_options(additional_units: additional_units)
Expand Down
Loading

0 comments on commit 683d2af

Please sign in to comment.