From f275cac9ddfb00d05435e73fc85f0a6c016095b8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bernd=20Ble=C3=9Fmann?= Date: Fri, 16 Oct 2015 01:35:05 +0200 Subject: [PATCH] Auftrags-Controller: PriceSources --- SL/Controller/Order.pm | 86 +++++++++++++++--- .../webpages/order/tabs/_item_input.html | 5 +- .../order/tabs/_price_sources_dialog.html | 89 +++++++++++++++++++ templates/webpages/order/tabs/_row.html | 48 +++++++--- templates/webpages/order/tabs/basic_data.html | 89 ++++++++++++++++++- 5 files changed, 291 insertions(+), 26 deletions(-) create mode 100644 templates/webpages/order/tabs/_price_sources_dialog.html diff --git a/SL/Controller/Order.pm b/SL/Controller/Order.pm index 1c713a72a..316198eed 100644 --- a/SL/Controller/Order.pm +++ b/SL/Controller/Order.pm @@ -18,12 +18,13 @@ use SL::DB::Employee; use SL::DB::Project; use SL::DB::Default; use SL::DB::Unit; +use SL::DB::Price; use SL::Helper::DateTime; use SL::Helper::CreatePDF qw(:all); use List::Util qw(max first); -use List::MoreUtils qw(none pairwise); +use List::MoreUtils qw(none pairwise first_index); use English qw(-no_match_vars); use File::Spec; @@ -315,17 +316,40 @@ sub action_add_item { my $item = SL::DB::OrderItem->new; $item->assign_attributes(%$form_attr); - my $part = SL::DB::Part->new(id => $form_attr->{parts_id})->load; - my $cv_method = $self->cv; - my $cv_discount = $self->order->$cv_method? $self->order->$cv_method->discount : 0.0; + my $part = SL::DB::Part->new(id => $form_attr->{parts_id})->load; + + my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order); + + 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{unit} = $part->unit; - $new_attr{sellprice} = $part->sellprice if ! $item->sellprice; - $new_attr{discount} = $cv_discount if ! $item->discount; + $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 @@ -364,6 +388,15 @@ sub action_recalc_amounts_and_taxes { $self->js->render(); } +sub action_price_popup { + my ($self) = @_; + + my $idx = first_index { $_ eq $::form->{item_id} } @{ $::form->{orderitem_ids} }; + my $item = $self->order->items->[$idx]; + + $self->render_price_dialog($item); +} + sub _js_redisplay_linetotals { my ($self) = @_; @@ -476,6 +509,27 @@ sub build_tax_rows { } +sub render_price_dialog { + my ($self, $record_item) = @_; + + my $price_source = SL::PriceSource->new(record_item => $record_item, record => $self->order); + + $self->js + ->run( + 'kivi.io.price_chooser_dialog', + t8('Available Prices'), + $self->render('order/tabs/_price_sources_dialog', { output => 0 }, price_source => $price_source) + ) + ->reinit_widgets; + +# if (@errors) { +# $self->js->text('#dialog_flash_error_content', join ' ', @errors); +# $self->js->show('#dialog_flash_error'); +# } + + $self->js->render; +} + sub _make_order { my ($self) = @_; @@ -491,7 +545,6 @@ sub _make_order { return $order; } - sub _recalc { my ($self) = @_; @@ -520,12 +573,10 @@ sub _get_unalterable_data { if ($item->id) { # load data from orderitems (db) my $db_item = SL::DB::OrderItem->new(id => $item->id)->load; - $item->$_($db_item->$_) for qw(active_discount_source active_price_source longdescription); + $item->$_($db_item->$_) for qw(longdescription); } else { # set data from part (or other sources) $item->longdescription($item->part->notes); - #$item->active_price_source(''); - #$item->active_discount_source(''); } # autovivify all cvars that are not in the form (cvars_by_config can do it). @@ -591,6 +642,13 @@ sub _pre_render { $self->{current_employee_id} = SL::DB::Manager::Employee->current->id; + foreach my $item (@{$self->order->items}) { + my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order); + $item->active_price_source( $price_source->price_from_source( $item->active_price_source )); + $item->active_discount_source($price_source->discount_from_source($item->active_discount_source)); + + } + $::request->{layout}->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery); } diff --git a/templates/webpages/order/tabs/_item_input.html b/templates/webpages/order/tabs/_item_input.html index f59c22628..aacaa4be4 100644 --- a/templates/webpages/order/tabs/_item_input.html +++ b/templates/webpages/order/tabs/_item_input.html @@ -16,7 +16,10 @@ [% L.part_picker('add_item.parts_id', '', fat_set_item=1, style='width: 300px', class="add_item_input") %] [% L.input_tag('add_item.description', '', class="add_item_input") %] - [% L.input_tag('add_item.qty_as_number', '', size = 5, style='text-align:right', class="add_item_input") %] + + [% L.input_tag('add_item.qty_as_number', '', size = 5, style='text-align:right', class="add_item_input") %] + [% L.hidden_tag('add_item.unit', '', class="add_item_input") %] + [% L.input_tag('add_item.sellprice_as_number', '', size = 10, style='text-align:right', class="add_item_input") %] [% L.input_tag('add_item.discount_as_percent', '', size = 5, style='text-align:right', class="add_item_input") %] [% L.button_tag('add_item()', LxERP.t8('Add part')) %] diff --git a/templates/webpages/order/tabs/_price_sources_dialog.html b/templates/webpages/order/tabs/_price_sources_dialog.html new file mode 100644 index 000000000..a73073e40 --- /dev/null +++ b/templates/webpages/order/tabs/_price_sources_dialog.html @@ -0,0 +1,89 @@ +[%- USE T8 %] +[%- USE HTML %] +[%- USE L %] +[%- USE LxERP %] +[% SET best_price = price_source.best_price %] +[% SET best_discount = price_source.best_discount %] +

[% 'Prices' | $T8 %]

+ + + + + + + + + + +[%- IF price_source.record_item.active_price_source %] + +[%- ELSE %] + +[%- END %] + + + + + + [%- FOREACH price IN price_source.available_prices %] + +[%- IF price_source.record_item.active_price_source != price.source %] + +[%- ELSIF price_source.record_item.sellprice * 1 != price.price * 1 %] + +[%- ELSE %] + +[% END %] + + +[% IF price.source == best_price.source %] + +[% ELSE %] + +[% END %] + + + [%- END %] +
[% 'Price Source' | $T8 %][% 'Price' | $T8 %][% 'Best Price' | $T8 %][% 'Details' | $T8 %]
[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource)') _ '\')', LxERP.t8('Select')) %][% 'Selected' | $T8 %][% 'None (PriceSource)' | $T8 %]-
[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Select')) %][% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Update Price')) %][% 'Selected' | $T8 %][% price.source_description | html %][% price.price_as_number %][% price.description | html %]
+ +

[% 'Discounts' | $T8 %]

+ + + + + + + + + + +[%- IF price_source.record_item.active_discount_source %] + +[%- ELSE %] + +[%- END %] + + + + + + [%- FOREACH price IN price_source.available_discounts %] + +[%- IF price_source.record_item.active_discount_source != price.source %] + +[%- ELSIF price_source.record_item.discount * 1 != price.discount * 1 %] + +[%- ELSE %] + +[% END %] + + +[% IF price.source == best_discount.source %] + +[% ELSE %] + +[% END %] + + + [%- END %] +
[% 'Price Source' | $T8 %][% 'Discount' | $T8 %][% 'Best Discount' | $T8 %][% 'Details' | $T8 %]
[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource Discount)') _ '\')', LxERP.t8('Select')) %][% 'Selected' | $T8 %][% 'None (PriceSource Discount)' | $T8 %]-
[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent _ '\')', LxERP.t8('Select')) %][% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent _ '\')', LxERP.t8('Update Discount')) %][% 'Selected' | $T8 %][% price.source_description | html %][% price.discount_as_percent %] %[% price.description | html %]
diff --git a/templates/webpages/order/tabs/_row.html b/templates/webpages/order/tabs/_row.html index a74863dec..009491bb3 100644 --- a/templates/webpages/order/tabs/_row.html +++ b/templates/webpages/order/tabs/_row.html @@ -7,6 +7,7 @@ + [% L.hidden_tag("orderitem_ids[+]", ID) %] [% L.hidden_tag("order.orderitems[+].id", ITEM.id, id='item_' _ ID) %] [% L.hidden_tag("order.orderitems[].parts_id", ITEM.parts_id) %] @@ -47,18 +48,45 @@ class="recalc") %] - [%- L.input_tag("order.orderitems[].sellprice_as_number", - ITEM.sellprice_as_number, - size = 10, - style='text-align:right', - class="recalc") %] + [%- L.button_tag("price_chooser_item_row(this)", + ITEM.active_price_source.source_description _ ' | ' _ ITEM.active_discount_source.source_description, + name = "price_chooser_button") %] - [%- L.input_tag("order.orderitems[].discount_as_percent", - ITEM.discount_as_percent, - size = 5, - style='text-align:right', - class="recalc") %] + [%- L.hidden_tag("order.orderitems[].active_price_source", ITEM.active_price_source.source) %] + [%- SET EDIT_PRICE = (AUTH.assert('edit_prices', 1) && ITEM.active_price_source.source == '') %] +
+ [%- L.input_tag("order.orderitems[].sellprice_as_number", + ITEM.sellprice_as_number, + size = 10, + style='text-align:right', + disabled=(EDIT_PRICE? '' : 1), + class="recalc reformat_number") %] +
+
+ [%- L.div_tag(ITEM.sellprice_as_number, name="sellprice_text", style='text-align:right') %] + [%- L.hidden_tag("order.orderitems[].sellprice_as_number", + ITEM.sellprice_as_number, + disabled=(EDIT_PRICE? 1 : '')) %] +
+ + + [%- L.hidden_tag("order.orderitems[].active_discount_source", ITEM.active_discount_source.source) %] + [%- SET EDIT_DISCOUNT = (AUTH.assert('edit_prices', 1) && ITEM.active_discount_source.source == '') %] +
+ [%- L.input_tag("order.orderitems[].discount_as_percent", + ITEM.discount_as_percent, + size = 5, + style='text-align:right', + disabled=(EDIT_DISCOUNT? '' : 1), + class="recalc reformat_number") %] +
+
+ [%- L.div_tag(ITEM.discount_as_percent, name="discount_text", style='text-align:right') %] + [%- L.hidden_tag("order.orderitems[].discount_as_percent", + ITEM.discount_as_percent, + disabled=(EDIT_DISCOUNT? 1 : '')) %] +
[%- L.div_tag(LxERP.format_amount(ITEM.linetotal, 2, 0), name="linetotal") %] diff --git a/templates/webpages/order/tabs/basic_data.html b/templates/webpages/order/tabs/basic_data.html index 8574424e7..934a38682 100644 --- a/templates/webpages/order/tabs/basic_data.html +++ b/templates/webpages/order/tabs/basic_data.html @@ -145,6 +145,7 @@ [%- 'Qty' | $T8 %] [%- 'Price Factor' | $T8 %] [%- 'Unit' | $T8 %] + [%- 'Price Source' | $T8 %] [%- 'Price' | $T8 %] [%- 'Discount' | $T8 %] [%- 'Extended' | $T8 %] @@ -272,6 +273,87 @@ function delete_order_item_row(clicked) { recalc_amounts_and_taxes(); } +function price_chooser_item_row(clicked) { + var row = $(clicked).parents("tbody").first(); + var item_id_dom = $(row).find('[name="orderitem_ids[+]"]'); + + var data = $('#order_form').serialize(); + data += '&action=Order/price_popup'; + data += '&item_id=' + item_id_dom.val(); + + $.post("controller.pl", data, kivi.eval_json_result); +} + +function update_price_source(item_id, source, descr, price_str) { + var row = $('#item_' + item_id).parents("tbody").first(); + var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]'); + var button_elt = $(row).find('[name="price_chooser_button"]'); + + button_elt.val(button_elt.val().replace(/.*\|/, descr + " |")); + source_elt.val(source); + + var editable_div_elt = $(row).find('[name="editable_price"]'); + var not_editable_div_elt = $(row).find('[name="not_editable_price"]'); + if ([%- AUTH.assert('edit_prices', 1) %] == 1 && source == '') { + // editable + $(editable_div_elt).show(); + $(not_editable_div_elt).hide(); + $(editable_div_elt).find(':input').prop("disabled", false); + $(not_editable_div_elt).find(':input').prop("disabled", true); + } else { + // not editable + $(editable_div_elt).hide(); + $(not_editable_div_elt).show(); + $(editable_div_elt).find(':input').prop("disabled", true); + $(not_editable_div_elt).find(':input').prop("disabled", false); + } + + if (price_str) { + var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]'); + var html_elt = $(row).find('[name="sellprice_text"]'); + price_elt.val(price_str); + html_elt.html(price_str); + recalc_amounts_and_taxes(); + } + + kivi.io.close_dialog(); +} + +function update_discount_source(item_id, source, descr, discount_str) { + var row = $('#item_' + item_id).parents("tbody").first(); + var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]'); + var button_elt = $(row).find('[name="price_chooser_button"]'); + + button_elt.val(button_elt.val().replace(/\|.*/, "| " + descr)); + source_elt.val(source); + + var editable_div_elt = $(row).find('[name="editable_discount"]'); + var not_editable_div_elt = $(row).find('[name="not_editable_discount"]'); + if ([%- AUTH.assert('edit_prices', 1) %] == 1 && source == '') { + // editable + $(editable_div_elt).show(); + $(not_editable_div_elt).hide(); + $(editable_div_elt).find(':input').prop("disabled", false); + $(not_editable_div_elt).find(':input').prop("disabled", true); + } else { + // not editable + $(editable_div_elt).hide(); + $(not_editable_div_elt).show(); + $(editable_div_elt).find(':input').prop("disabled", true); + $(not_editable_div_elt).find(':input').prop("disabled", false); + } + + if (discount_str) { + var discount_elt = $(row).find('[name="order.orderitems[].discount_as_percent"]'); + var html_elt = $(row).find('[name="discount_text"]'); + discount_elt.val(discount_str); + html_elt.html(discount_str); + recalc_amounts_and_taxes(); + } + + kivi.io.close_dialog(); +} + function reformat_number(event) { $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2)); } @@ -357,8 +439,13 @@ close_email_dialog = function() { $(function(){ $('#order_[%- cv_id %]').change(reload_cv_dependend_selections); - $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) }); + [%- IF SELF.cv == 'customer' %] + $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) }); + [%- ELSE %] + $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) }); + [%- END %] $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) }); + $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) }); $('.add_item_input').keydown(function(event) { if(event.keyCode == 13) { event.preventDefault(); -- 2.20.1