Revision f275cac9
Von Bernd Bleßmann vor etwa 9 Jahren hinzugefügt
SL/Controller/Order.pm | ||
---|---|---|
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;
|
||
|
||
... | ... | |
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
|
||
... | ... | |
$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) = @_;
|
||
|
||
... | ... | |
}
|
||
|
||
|
||
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) = @_;
|
||
|
||
... | ... | |
return $order;
|
||
}
|
||
|
||
|
||
sub _recalc {
|
||
my ($self) = @_;
|
||
|
||
... | ... | |
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).
|
||
... | ... | |
|
||
$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);
|
||
}
|
||
|
templates/webpages/order/tabs/_item_input.html | ||
---|---|---|
<tr valign="top" class="listrow">
|
||
<td>[% L.part_picker('add_item.parts_id', '', fat_set_item=1, style='width: 300px', class="add_item_input") %]</td>
|
||
<td>[% L.input_tag('add_item.description', '', class="add_item_input") %]</td>
|
||
<td>[% L.input_tag('add_item.qty_as_number', '', size = 5, style='text-align:right', class="add_item_input") %]</td>
|
||
<td>
|
||
[% 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") %]
|
||
</td>
|
||
<td>[% L.input_tag('add_item.sellprice_as_number', '', size = 10, style='text-align:right', class="add_item_input") %]</td>
|
||
<td>[% L.input_tag('add_item.discount_as_percent', '', size = 5, style='text-align:right', class="add_item_input") %]</td>
|
||
<td>[% L.button_tag('add_item()', LxERP.t8('Add part')) %]</td>
|
templates/webpages/order/tabs/_price_sources_dialog.html | ||
---|---|---|
[%- USE T8 %]
|
||
[%- USE HTML %]
|
||
[%- USE L %]
|
||
[%- USE LxERP %]
|
||
[% SET best_price = price_source.best_price %]
|
||
[% SET best_discount = price_source.best_discount %]
|
||
<h2>[% 'Prices' | $T8 %]</h2>
|
||
|
||
<table>
|
||
<tr class='listheading'>
|
||
<th></th>
|
||
<th>[% 'Price Source' | $T8 %]</th>
|
||
<th>[% 'Price' | $T8 %]</th>
|
||
<th>[% 'Best Price' | $T8 %]</th>
|
||
<th>[% 'Details' | $T8 %]</th>
|
||
</tr>
|
||
<tr class='listrow'>
|
||
[%- IF price_source.record_item.active_price_source %]
|
||
<td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource)') _ '\')', LxERP.t8('Select')) %]</td>
|
||
[%- ELSE %]
|
||
<td><b>[% 'Selected' | $T8 %]</b></td>
|
||
[%- END %]
|
||
<td>[% 'None (PriceSource)' | $T8 %]</td>
|
||
<td>-</td>
|
||
<td></td>
|
||
<td></td>
|
||
</tr>
|
||
[%- FOREACH price IN price_source.available_prices %]
|
||
<tr class='listrow'>
|
||
[%- IF price_source.record_item.active_price_source != price.source %]
|
||
<td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Select')) %]</td>
|
||
[%- ELSIF price_source.record_item.sellprice * 1 != price.price * 1 %]
|
||
<td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Update Price')) %]</td>
|
||
[%- ELSE %]
|
||
<td><b>[% 'Selected' | $T8 %]</b></td>
|
||
[% END %]
|
||
<td>[% price.source_description | html %]</td>
|
||
<td>[% price.price_as_number %]</td>
|
||
[% IF price.source == best_price.source %]
|
||
<td align='center'>•</td>
|
||
[% ELSE %]
|
||
<td></td>
|
||
[% END %]
|
||
<td>[% price.description | html %]</td>
|
||
</tr>
|
||
[%- END %]
|
||
</table>
|
||
|
||
<h2>[% 'Discounts' | $T8 %]</h2>
|
||
|
||
<table>
|
||
<tr class='listheading'>
|
||
<th></th>
|
||
<th>[% 'Price Source' | $T8 %]</th>
|
||
<th>[% 'Discount' | $T8 %]</th>
|
||
<th>[% 'Best Discount' | $T8 %]</th>
|
||
<th>[% 'Details' | $T8 %]</th>
|
||
</tr>
|
||
<tr class='listrow'>
|
||
[%- IF price_source.record_item.active_discount_source %]
|
||
<td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource Discount)') _ '\')', LxERP.t8('Select')) %]</td>
|
||
[%- ELSE %]
|
||
<td><b>[% 'Selected' | $T8 %]</b></td>
|
||
[%- END %]
|
||
<td>[% 'None (PriceSource Discount)' | $T8 %]</td>
|
||
<td>-</td>
|
||
<td></td>
|
||
<td></td>
|
||
</tr>
|
||
[%- FOREACH price IN price_source.available_discounts %]
|
||
<tr class='listrow'>
|
||
[%- IF price_source.record_item.active_discount_source != price.source %]
|
||
<td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent _ '\')', LxERP.t8('Select')) %]</td>
|
||
[%- ELSIF price_source.record_item.discount * 1 != price.discount * 1 %]
|
||
<td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent _ '\')', LxERP.t8('Update Discount')) %]</td>
|
||
[%- ELSE %]
|
||
<td><b>[% 'Selected' | $T8 %]</b></td>
|
||
[% END %]
|
||
<td>[% price.source_description | html %]</td>
|
||
<td>[% price.discount_as_percent %] %</td>
|
||
[% IF price.source == best_discount.source %]
|
||
<td align='center'>•</td>
|
||
[% ELSE %]
|
||
<td></td>
|
||
[% END %]
|
||
<td>[% price.description | html %]</td>
|
||
</tr>
|
||
[%- END %]
|
||
</table>
|
templates/webpages/order/tabs/_row.html | ||
---|---|---|
|
||
<tr class="listrow0">
|
||
<td style='display:none'>
|
||
[% 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) %]
|
||
</td>
|
||
... | ... | |
class="recalc") %]
|
||
</td>
|
||
<td>
|
||
[%- 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") %]
|
||
</td>
|
||
<td>
|
||
[%- 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 == '') %]
|
||
<div name="editable_price" [%- IF !EDIT_PRICE %]style="display:none"[%- END %]>
|
||
[%- 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") %]
|
||
</div>
|
||
<div name="not_editable_price" [%- IF EDIT_PRICE %]style="display:none"[%- END %]>
|
||
[%- 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 : '')) %]
|
||
</div>
|
||
</td>
|
||
<td>
|
||
[%- 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 == '') %]
|
||
<div name="editable_discount" [%- IF !EDIT_DISCOUNT %]style="display:none"[%- END %]>
|
||
[%- 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") %]
|
||
</div>
|
||
<div name="not_editable_discount" [%- IF EDIT_DISCOUNT %]style="display:none"[%- END %]>
|
||
[%- 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 : '')) %]
|
||
</div>
|
||
</td>
|
||
<td align="right">
|
||
[%- L.div_tag(LxERP.format_amount(ITEM.linetotal, 2, 0), name="linetotal") %]
|
templates/webpages/order/tabs/basic_data.html | ||
---|---|---|
<th class="listheading" nowrap width="5" >[%- 'Qty' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="5" >[%- 'Price Factor' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="5" >[%- 'Unit' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="5" >[%- 'Price Source' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="15">[%- 'Price' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="5" >[%- 'Discount' | $T8 %] </th>
|
||
<th class="listheading" nowrap width="10">[%- 'Extended' | $T8 %] </th>
|
||
... | ... | |
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));
|
||
}
|
||
... | ... | |
|
||
$(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();
|
Auch abrufbar als: Unified diff
Auftrags-Controller: PriceSources