From 91abaf6cbfa5bb429df7fce3748b3d37082551ad Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bernd=20Ble=C3=9Fmann?= Date: Mon, 2 Nov 2015 15:48:11 +0100 Subject: [PATCH] Auftrags-Controller: Mehrfach-Artikelauswahl mit Mengeneingabe. --- SL/Controller/Order.pm | 171 +++++++++++++----- js/locale/de.js | 1 + locale/de/all | 4 + .../order/tabs/_multi_items_dialog.html | 64 +++++++ .../order/tabs/_multi_items_result.html | 37 ++++ templates/webpages/order/tabs/basic_data.html | 24 +++ 6 files changed, 258 insertions(+), 43 deletions(-) create mode 100644 templates/webpages/order/tabs/_multi_items_dialog.html create mode 100644 templates/webpages/order/tabs/_multi_items_result.html diff --git a/SL/Controller/Order.pm b/SL/Controller/Order.pm index 80dc814c6..5828132b3 100644 --- a/SL/Controller/Order.pm +++ b/SL/Controller/Order.pm @@ -20,10 +20,13 @@ use SL::DB::Project; use SL::DB::Default; use SL::DB::Unit; use SL::DB::Price; +use SL::DB::Part; use SL::Helper::DateTime; use SL::Helper::CreatePDF qw(:all); +use SL::Controller::Helper::GetModels; + use List::Util qw(max first); use List::MoreUtils qw(none pairwise first_index); use English qw(-no_match_vars); @@ -31,7 +34,7 @@ use File::Spec; use Rose::Object::MakeMethods::Generic ( - 'scalar --get_set_init' => [ qw(order valid_types type cv p) ], + 'scalar --get_set_init' => [ qw(order valid_types type cv p multi_items_models) ], ); @@ -333,63 +336,76 @@ sub action_add_item { return unless $form_attr->{parts_id}; - my $item = SL::DB::OrderItem->new; - $item->assign_attributes(%$form_attr); + my $item = _make_item($self->order, $form_attr); + $self->order->add_items($item); - my $part = SL::DB::Part->new(id => $form_attr->{parts_id})->load; + $self->_recalc(); - my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order); + my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000); + my $row_as_html = $self->p->render('order/tabs/_row', ITEM => $item, ID => $item_id); - my $price_src; - if ($item->sellprice) { - $price_src = $price_source->price_from_source(""); - $price_src->price($item->sellprice); - } else { - $price_src = $price_source->best_price - ? $price_source->best_price - : $price_source->price_from_source(""); - $price_src->price(0) if !$price_source->best_price; - } + $self->js + ->append('#row_table_id', $row_as_html) + ->val('.add_item_input', '') + ->run('row_table_scroll_down') + ->run('row_set_keyboard_events_by_id', $item_id) + ->on('.recalc', 'change', 'recalc_amounts_and_taxes') + ->on('.reformat_number', 'change', 'reformat_number') + ->focus('#add_item_parts_id_name'); - my $discount_src; - if ($item->discount) { - $discount_src = $price_source->discount_from_source(""); - $discount_src->discount($item->discount); + $self->_js_redisplay_amounts_and_taxes; + $self->js->render(); +} + +sub action_show_multi_items_dialog { + require SL::DB::PartsGroup; + $_[0]->render('order/tabs/_multi_items_dialog', { layout => 0 }, + all_partsgroups => SL::DB::Manager::PartsGroup->get_all); +} + +sub action_multi_items_update_result { + my $max_count = 100; + my $count = $_[0]->multi_items_models->count; + + if ($count == 0) { + my $text = SL::Presenter::EscapedText->new(text => $::locale->text('No results.')); + $_[0]->render($text, { layout => 0 }); + } elsif ($count > $max_count) { + my $text = SL::Presenter::EscapedText->new(text => $::locale->text('Too many results (#1 from #2).', $count, $max_count)); + $_[0]->render($text, { layout => 0 }); } else { - $discount_src = $price_source->best_discount - ? $price_source->best_discount - : $price_source->discount_from_source(""); - $discount_src->discount(0) if !$price_source->best_discount; + my $multi_items = $_[0]->multi_items_models->get; + $_[0]->render('order/tabs/_multi_items_result', { layout => 0 }, + multi_items => $multi_items); } +} - my %new_attr; - $new_attr{part} = $part; - $new_attr{description} = $part->description if ! $item->description; - $new_attr{qty} = 1.0 if ! $item->qty; - $new_attr{sellprice} = $price_src->price; - $new_attr{discount} = $discount_src->discount; - $new_attr{active_price_source} = $price_src; - $new_attr{active_discount_source} = $discount_src; - - # add_custom_variables adds cvars to an orderitem with no cvars for saving, but - # they cannot be retrieved via custom_variables until the order/orderitem is - # saved. Adding empty custom_variables to new orderitem here solves this problem. - $new_attr{custom_variables} = []; +sub action_add_multi_items { + my ($self) = @_; - $item->assign_attributes(%new_attr); + my @form_attr = grep { $_->{qty_as_number} } @{ $::form->{add_multi_items} }; + return $self->js->render() unless scalar @form_attr; - $self->order->add_items($item); + my @items; + foreach my $attr (@form_attr) { + push @items, _make_item($self->order, $attr); + } + $self->order->add_items(@items); $self->_recalc(); - my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000); - my $row_as_html = $self->p->render('order/tabs/_row', ITEM => $item, ID => $item_id); + foreach my $item (@items) { + my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000); + my $row_as_html = $self->p->render('order/tabs/_row', ITEM => $item, ID => $item_id); + + $self->js + ->append('#row_table_id', $row_as_html) + ->run('row_set_keyboard_events_by_id', $item_id); + } $self->js - ->append('#row_table_id', $row_as_html) - ->val('.add_item_input', '') + ->run('close_multi_items_dialog') ->run('row_table_scroll_down') - ->run('row_set_keyboard_events_by_id', $item_id) ->on('.recalc', 'change', 'recalc_amounts_and_taxes') ->on('.reformat_number', 'change', 'reformat_number') ->focus('#add_item_parts_id_name'); @@ -483,6 +499,23 @@ sub init_order { _make_order(); } +sub init_multi_items_models { + SL::Controller::Helper::GetModels->new( + controller => $_[0], + model => 'Part', + with_objects => [ qw(unit_obj) ], + disable_plugin => 'paginated', + source => $::form->{multi_items}, + sorted => { + _default => { + by => 'partnumber', + dir => 1, + }, + partnumber => t8('Partnumber'), + description => t8('Description')} + ); +} + sub _check_auth { my ($self) = @_; @@ -565,6 +598,58 @@ sub _make_order { return $order; } +sub _make_item { + my ($record, $attr) = @_; + + my $item = SL::DB::OrderItem->new; + $item->assign_attributes(%$attr); + + my $part = SL::DB::Part->new(id => $attr->{parts_id})->load; + my $price_source = SL::PriceSource->new(record_item => $item, record => $record); + + $item->unit($part->unit) if !$item->unit; + + my $price_src; + if ($item->sellprice) { + $price_src = $price_source->price_from_source(""); + $price_src->price($item->sellprice); + } else { + $price_src = $price_source->best_price + ? $price_source->best_price + : $price_source->price_from_source(""); + $price_src->price(0) if !$price_source->best_price; + } + + my $discount_src; + if ($item->discount) { + $discount_src = $price_source->discount_from_source(""); + $discount_src->discount($item->discount); + } else { + $discount_src = $price_source->best_discount + ? $price_source->best_discount + : $price_source->discount_from_source(""); + $discount_src->discount(0) if !$price_source->best_discount; + } + + my %new_attr; + $new_attr{part} = $part; + $new_attr{description} = $part->description if ! $item->description; + $new_attr{qty} = 1.0 if ! $item->qty; + $new_attr{sellprice} = $price_src->price; + $new_attr{discount} = $discount_src->discount; + $new_attr{active_price_source} = $price_src; + $new_attr{active_discount_source} = $discount_src; + + # add_custom_variables adds cvars to an orderitem with no cvars for saving, but + # they cannot be retrieved via custom_variables until the order/orderitem is + # saved. Adding empty custom_variables to new orderitem here solves this problem. + $new_attr{custom_variables} = []; + + $item->assign_attributes(%new_attr); + + return $item; +} + sub _recalc { my ($self) = @_; diff --git a/js/locale/de.js b/js/locale/de.js index 5bbfceeff..c97b7c621 100644 --- a/js/locale/de.js +++ b/js/locale/de.js @@ -2,6 +2,7 @@ namespace("kivi").setupLocale({ "A transaction description is required.":"Die Vorgangsbezeichnung muss eingegeben werden.", "Add function block":"Funktionsblock hinzufügen", "Add linked record":"Verknüpften Beleg hinzufügen", +"Add multiple items":"Mehrere Artikel hinzufügen", "Add picture":"Bild hinzufügen", "Add picture to text block":"Bild dem Textblock hinzufügen", "Add section":"Abschnitt hinzufügen", diff --git a/locale/de/all b/locale/de/all index b3ac925b6..445b9becb 100755 --- a/locale/de/all +++ b/locale/de/all @@ -187,6 +187,7 @@ $self->{texts} = { 'Add link: select records to link with' => 'Verknüpfungen hinzufügen: zu verknüpfende Belege auswählen', 'Add linked record' => 'Verknüpften Beleg hinzufügen', 'Add links' => 'Verknüpfungen hinzufügen', + 'Add multiple items' => 'Mehrere Artikel hinzufügen', 'Add new currency' => 'Neue Währung hinzufügen', 'Add new custom variable' => 'Neue benutzerdefinierte Variable erfassen', 'Add new price rule item' => 'Neue Bedingung hinzufügen', @@ -1783,6 +1784,7 @@ $self->{texts} = { 'No requirement spec statuses has been created yet.' => 'Es wurden noch keine Pflichtenheftstatus angelegt.', 'No requirement spec templates have been created yet.' => 'Es wurden noch keine Pflichtenheftvorlagen angelegt.', 'No requirement spec type has been created yet.' => 'Es wurden noch keine Pflichtenhefttypen angelegt.', + 'No results.' => 'Keine Artikel', 'No risks level has been created yet.' => 'Es wurden noch keine Risikograde angelegt.', 'No sections created yet' => 'Keine Abschnitte erstellt', 'No sections have been created so far.' => 'Bisher wurden noch keine Abschnitte angelegt.', @@ -3079,6 +3081,7 @@ $self->{texts} = { 'To continue please change the taxkey 0 to another value.' => 'Um fortzufahren, ändern Sie bitte den Steuerschlüssel 0 auf einen anderen Wert.', 'To user login' => 'Zum Benutzerlogin', 'Toggle marker' => 'Markierung umschalten', + 'Too many results (#1 from #2).' => 'Zu viele Artikel (#1 von #2)', 'Top' => 'Oben', 'Top (CSS)' => 'Oben (mit CSS)', 'Top (Javascript)' => 'Oben (mit Javascript)', @@ -3424,6 +3427,7 @@ $self->{texts} = { 'follow_up_list' => 'wiedervorlageliste', 'for' => 'für', 'for Period' => 'für den Zeitraum', + 'for all' => 'für alle', 'for date' => 'zum Stichtag', 'found' => 'Gefunden', 'from (time)' => 'von', diff --git a/templates/webpages/order/tabs/_multi_items_dialog.html b/templates/webpages/order/tabs/_multi_items_dialog.html new file mode 100644 index 000000000..cb1fc3ea8 --- /dev/null +++ b/templates/webpages/order/tabs/_multi_items_dialog.html @@ -0,0 +1,64 @@ +[%- USE T8 %][%- USE HTML %][%- USE L %][%- USE LxERP %] + +
+ + + + + + + + +
[%- LxERP.t8("Description") %]/[%- LxERP.t8("Partnumber") %]:[%- L.input_tag('multi_items.filter.all:substr:multi::ilike', '') %][%- LxERP.t8("Group") %][%- L.select_tag('multi_items.filter.partsgroup_id', all_partsgroups, title_key='displayable_name', value_key='id', with_empty=1) %]
+ +[% L.button_tag('update_result()', LxERP.t8('Filter')) %] +[% 'Reset' | $T8 %] + +
+
+
+ +[% L.button_tag('add_multi_items()', LxERP.t8('Continue')) %] +[%- LxERP.t8("Cancel") %] + + + +
diff --git a/templates/webpages/order/tabs/_multi_items_result.html b/templates/webpages/order/tabs/_multi_items_result.html new file mode 100644 index 000000000..248fe8f3c --- /dev/null +++ b/templates/webpages/order/tabs/_multi_items_result.html @@ -0,0 +1,37 @@ +[%- USE T8 %][%- USE HTML %][%- USE L %][%- USE LxERP %] + + + + + + + + + [%- FOREACH item = multi_items %] + + + + + + + + [%- END %] +
[% 'for all' | $T8 %] + [% L.input_tag("multi_items.all_qty", '', size = 5, style='text-align:right') %]

+ [% L.hidden_tag("add_multi_items[+].parts_id", item.id) %] + [% L.input_tag("add_multi_items[].qty_as_number", '', size = 5, style='text-align:right', + class = 'multi_items_qty', onclick = 'set_qty_to_one(this)') %] + [% HTML.escape(item.unit) %][% HTML.escape(item.partnumber) %][% HTML.escape(item.description) %]
+ + diff --git a/templates/webpages/order/tabs/basic_data.html b/templates/webpages/order/tabs/basic_data.html index 0fd301d2c..27032e0e5 100644 --- a/templates/webpages/order/tabs/basic_data.html +++ b/templates/webpages/order/tabs/basic_data.html @@ -143,6 +143,8 @@ [%- PROCESS order/tabs/_item_input.html %] + [% L.button_tag('show_multi_items_dialog()', LxERP.t8('Add multiple parts')) %] +
@@ -280,6 +282,28 @@ function add_item() { $.post("controller.pl", data, kivi.eval_json_result); } +function show_multi_items_dialog() { + if (!check_cv()) return; + + kivi.popup_dialog({ + url: 'controller.pl?action=Order/show_multi_items_dialog', + data: { type: $('#type').val(), + callback: 'Order/add_multi_items', + callback_data_id: 'order_form' }, + id: 'jq_multi_items_dialog', + dialog: { + title: kivi.t8('Add multiple items'), + width: 800, + height: 500 + } + }); + return true; +} + +function close_multi_items_dialog() { + $('#jq_multi_items_dialog').dialog('close'); +}; + function delete_order_item_row(clicked) { var row = $(clicked).parents("tbody").first(); $(row).remove(); -- 2.20.1