Revision 007fe204
Von Tamino Steinert vor mehr als 1 Jahr hinzugefügt
| SL/Controller/Part.pm | ||
|---|---|---|
|
sub action_showdetails {
|
||
|
my ($self, %params) = @_;
|
||
|
|
||
|
eval {
|
||
|
my @bindata;
|
||
|
my $bins = SL::DB::Manager::Bin->get_all(with_objects => ['warehouse' ]);
|
||
|
my %bins_by_id = map { $_->id => $_ } @$bins;
|
||
|
my $inventories = SL::DB::Manager::Inventory->get_all(where => [ parts_id => $self->part->id],
|
||
|
with_objects => ['parts', 'trans_type' ], sort_by => 'bin_id ASC');
|
||
|
foreach my $bin (@{ $bins }) {
|
||
|
$bin->{qty} = 0;
|
||
|
}
|
||
|
|
||
|
foreach my $inv (@{ $inventories }) {
|
||
|
my $bin = $bins_by_id{ $inv->bin_id };
|
||
|
$bin->{qty} += $inv->qty;
|
||
|
$bin->{unit} = $inv->parts->unit;
|
||
|
$bin->{reserved} = defined $inv->reserve_for_id ? 1 : 0;
|
||
|
}
|
||
|
my $sum = 0;
|
||
|
my $reserve_sum = 0;
|
||
|
for my $bin (@{ $bins }) {
|
||
|
push @bindata , {
|
||
|
'warehouse' => $bin->warehouse->forreserve ? $bin->warehouse->description.' (R)' : $bin->warehouse->description,
|
||
|
'description' => $bin->description,
|
||
|
'qty' => $bin->{qty},
|
||
|
'unit' => $bin->{unit},
|
||
|
} if $bin->{qty} != 0;
|
||
|
|
||
|
$sum += $bin->{qty};
|
||
|
if($bin->warehouse->forreserve || defined $bin->warehouse->{reserve_for_id}){
|
||
|
$reserve_sum += $bin->{qty};
|
||
|
}
|
||
|
}
|
||
|
# Einfacher ? $sum = $self->part->onhand
|
||
|
my $todate = DateTime->now_local;
|
||
|
my $fromdate = DateTime->now_local->add_duration(DateTime::Duration->new(years => -1));
|
||
|
my $average = 0;
|
||
|
foreach my $inv (@{ $inventories }) {
|
||
|
$average += abs($inv->qty) if $inv->shippingdate && $inv->trans_type->direction eq 'out' &&
|
||
|
DateTime->compare($inv->shippingdate,$fromdate) != -1 &&
|
||
|
DateTime->compare($inv->shippingdate,$todate) == -1;
|
||
|
}
|
||
|
my $openitems = SL::DB::Manager::OrderItem->get_all(where => [ parts_id => $self->part->id, 'order.closed' => 0 ],
|
||
|
with_objects => ['order'],);
|
||
|
my ($not_delivered, $ordered) = 0;
|
||
|
for my $openitem (@{ $openitems }) {
|
||
|
if($openitem -> order -> type eq 'sales_order') {
|
||
|
$not_delivered += $openitem->qty - $openitem->shipped_qty;
|
||
|
} elsif ( $openitem->order->type eq 'purchase_order' ) {
|
||
|
$ordered += $openitem->qty - $openitem->delivered_qty;
|
||
|
}
|
||
|
}
|
||
|
my $print_form = Form->new('');
|
||
|
my $part = $self->part;
|
||
|
|
||
|
my $stock_amounts = $self->part->get_simple_stock_sql;
|
||
|
$print_form->{type} = 'part';
|
||
|
$print_form->{printers} = SL::DB::Manager::Printer->get_all_sorted;
|
||
|
my $output = SL::Presenter->get->render('part/showdetails',
|
||
|
part => $self->part,
|
||
|
BINS => \@bindata,
|
||
|
stock_amounts => $stock_amounts,
|
||
|
average => $average/12,
|
||
|
fromdate => $fromdate,
|
||
|
todate => $todate,
|
||
|
sum => $sum,
|
||
|
reserve_sum => $reserve_sum,
|
||
|
not_delivered => $not_delivered,
|
||
|
ordered => $ordered,
|
||
|
type_beleg => $::form->{type},
|
||
|
type_id => $::form->{type_id},
|
||
|
maker_id => $::form->{maker_id},
|
||
|
drawing => $::form->{drawing},
|
||
|
my @bindata;
|
||
|
my $bins = SL::DB::Manager::Bin->get_all(with_objects => ['warehouse' ]);
|
||
|
my %bins_by_id = map { $_->id => $_ } @$bins;
|
||
|
my $inventories = SL::DB::Manager::Inventory->get_all(where => [ parts_id => $self->part->id],
|
||
|
with_objects => ['parts', 'trans_type' ], sort_by => 'bin_id ASC');
|
||
|
foreach my $bin (@{ $bins }) {
|
||
|
$bin->{qty} = 0;
|
||
|
}
|
||
|
|
||
|
foreach my $inv (@{ $inventories }) {
|
||
|
my $bin = $bins_by_id{ $inv->bin_id };
|
||
|
$bin->{qty} += $inv->qty;
|
||
|
$bin->{unit} = $inv->parts->unit;
|
||
|
}
|
||
|
my $sum = 0;
|
||
|
for my $bin (@{ $bins }) {
|
||
|
push @bindata , {
|
||
|
'warehouse' => $bin->warehouse->description,
|
||
|
'description' => $bin->description,
|
||
|
'qty' => $bin->{qty},
|
||
|
'unit' => $bin->{unit},
|
||
|
} if $bin->{qty} != 0;
|
||
|
|
||
|
$sum += $bin->{qty};
|
||
|
}
|
||
|
|
||
|
my $todate = DateTime->now_local;
|
||
|
my $fromdate = DateTime->now_local->add_duration(DateTime::Duration->new(years => -1));
|
||
|
my $average = 0;
|
||
|
foreach my $inv (@{ $inventories }) {
|
||
|
$average += abs($inv->qty) if $inv->shippingdate && $inv->trans_type->direction eq 'out' &&
|
||
|
DateTime->compare($inv->shippingdate,$fromdate) != -1 &&
|
||
|
DateTime->compare($inv->shippingdate,$todate) == -1;
|
||
|
}
|
||
|
my $openitems = SL::DB::Manager::OrderItem->get_all(where => [ parts_id => $self->part->id, 'order.closed' => 0 ],
|
||
|
with_objects => ['order'],);
|
||
|
my ($not_delivered, $ordered) = 0;
|
||
|
for my $openitem (@{ $openitems }) {
|
||
|
if($openitem -> order -> type eq 'sales_order') {
|
||
|
$not_delivered += $openitem->qty - $openitem->shipped_qty;
|
||
|
} elsif ( $openitem->order->type eq 'purchase_order' ) {
|
||
|
$ordered += $openitem->qty - $openitem->delivered_qty;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $stock_amounts = $self->part->get_simple_stock_sql;
|
||
|
|
||
|
my $output = SL::Presenter->get->render('part/showdetails',
|
||
|
part => $self->part,
|
||
|
stock_amounts => $stock_amounts,
|
||
|
average => $average/12,
|
||
|
fromdate => $fromdate,
|
||
|
todate => $todate,
|
||
|
sum => $sum,
|
||
|
not_delivered => $not_delivered,
|
||
|
ordered => $ordered,
|
||
|
print_options => SL::Helper::PrintOptions->get_print_options(
|
||
|
form => $print_form,
|
||
|
options => {dialog_name_prefix => 'print_options.',
|
||
|
show_headers => 1,
|
||
|
no_queue => 1,
|
||
|
no_postscript => 1,
|
||
|
no_opendocument => 1,
|
||
|
hide_language_id_print => 1,
|
||
|
no_html => 1},
|
||
|
form => Form->new(
|
||
|
type => 'part',
|
||
|
printers => SL::DB::Manager::Printer->get_all_sorted,
|
||
|
),
|
||
|
options => {
|
||
|
dialog_name_prefix => 'print_options.',
|
||
|
show_headers => 1,
|
||
|
no_queue => 1,
|
||
|
no_postscript => 1,
|
||
|
no_opendocument => 1,
|
||
|
hide_language_id_print => 1,
|
||
|
no_html => 1,
|
||
|
},
|
||
|
),
|
||
|
);
|
||
|
$self->render(\$output, { layout => 0, process => 0 });
|
||
|
1;
|
||
|
} or do {
|
||
|
};
|
||
|
);
|
||
|
$self->render(\$output, { layout => 0, process => 0 });
|
||
|
}
|
||
|
|
||
|
sub action_print_label {
|
||
| js/kivi.DispositionManager.js | ||
|---|---|---|
|
|
||
|
ns.show_detail_dialog = function(part_id,partnumber) {
|
||
|
if ( part_id && partnumber ) {
|
||
|
var title = kivi.t8('Details of article number "#1"',[partnumber]);
|
||
|
kivi.popup_dialog({
|
||
|
url: 'controller.pl',
|
||
|
data: {
|
||
|
action: 'Part/showdetails',
|
||
|
id : part_id,
|
||
|
},
|
||
|
id: 'detail_menu',
|
||
|
dialog: { title: title
|
||
|
, width: 1000
|
||
|
, height: 450
|
||
|
, modal: false }
|
||
|
});
|
||
|
var title = kivi.t8('Details of article number "#1"',[partnumber]);
|
||
|
kivi.popup_dialog({
|
||
|
url: 'controller.pl',
|
||
|
data: {
|
||
|
action: 'Part/showdetails',
|
||
|
id : part_id,
|
||
|
},
|
||
|
id: 'detail_menu',
|
||
|
dialog: {
|
||
|
title: title,
|
||
|
width: 900,
|
||
|
height: 600,
|
||
|
modal: false
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
| templates/design40_webpages/part/showdetails.html | ||
|---|---|---|
|
[%- USE LxERP -%][% USE L %][% USE HTML %][%- USE JavaScript -%][% USE T8 %][%- USE Dumper %]
|
||
|
|
||
|
<div class="wrapper">
|
||
|
<div class="col"> <!-- part info -->
|
||
|
<div class="wrapper">
|
||
|
<table class="tbl-horizontal">
|
||
|
<tbody>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Description') %]</b></td>
|
||
|
<td>[% part.description %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Default Warehouse') %]</b></td>
|
||
|
<td>[% part.warehouse.description %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Default Bin') %]</b></td>
|
||
|
<td>[% part.bin.description %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('ROP') %]</b></td><td>[% part.rop_as_number %]</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
|
||
|
<div class="wrapper">
|
||
|
<table class="tbl-list" style="margin-right: 1em;">
|
||
|
[%- IF stock_amounts.size %]
|
||
|
<thead>
|
||
|
<tr class='listheading'>
|
||
|
<th>[% 'Warehouse' | $T8 %]</th>
|
||
|
<th>[% 'Bin' | $T8 %]</th>
|
||
|
<th>[% 'Chargenumber' | $T8 %]</th>
|
||
|
<th>[% 'Qty' | $T8 %]</th>
|
||
|
<th>[% 'Unit' | $T8 %]</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
[% FOREACH stock = stock_amounts %]
|
||
|
<tr>
|
||
|
<td>[% HTML.escape(stock.warehouse_description) %]</td>
|
||
|
<td>[% HTML.escape(stock.bin_description) %]</td>
|
||
|
<td>[% HTML.escape(stock.chargenumber) %]</td>
|
||
|
<td class='numeric'>[% LxERP.format_amount(stock.qty, dec) %]</td>
|
||
|
<td>[% HTML.escape(stock.unit) %]</td>
|
||
|
</tr>
|
||
|
[% IF stock.wh_lead != stock.warehouse_description %]
|
||
|
<tr>
|
||
|
<th><b>[% HTML.escape(stock.warehouse_description) %]</b></th>
|
||
|
<td></td>
|
||
|
<td></td>
|
||
|
<td class='numeric bold'>[% LxERP.format_amount(stock.wh_run_qty, dec) %]</td>
|
||
|
<td></td>
|
||
|
</tr>
|
||
|
[% END %]
|
||
|
[% IF loop.last %]
|
||
|
<tr>
|
||
|
<th><b>[% 'Total' | $T8 %]</b></th>
|
||
|
<td></td>
|
||
|
<td></td>
|
||
|
<td class='numeric bold'>[% LxERP.format_amount(stock.run_qty, dec) %]</td>
|
||
|
<td></td>
|
||
|
</tr>
|
||
|
[% END %]
|
||
|
[% END %]
|
||
|
</tbody>
|
||
|
[% ELSE %]
|
||
|
<thead>
|
||
|
<th>
|
||
|
<p>[% 'No transactions yet.' | $T8 %]</p>
|
||
|
</th>
|
||
|
</thead>
|
||
|
[% END %]
|
||
|
</table>
|
||
|
</div>
|
||
|
|
||
|
<div class="wrapper">
|
||
|
<table class="tbl-horizontal">
|
||
|
<tbody>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Sum Amount') %]</b></td>
|
||
|
<td>[% LxERP.format_amount(sum, 2) %] [% part.unit %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Not delivered amount') %]</b></td>
|
||
|
<td>[% LxERP.format_amount(not_delivered, 2) %] [% part.unit %]
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Ordered, but not delivered (purchase)') %]</b></td>
|
||
|
<td>[% LxERP.format_amount(ordered, 2) %] [% part.unit %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Available amount') %]</b></td>
|
||
|
<td>[% LxERP.format_amount(part.onhandqty, 2) %] [% part.unit %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Consume average') %]</b></td>
|
||
|
<td>[% LxERP.format_amount(average, 2) %] [% part.unit %] [% LxERP.t8('per month') %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td colspan="2" nowrap>([% LxERP.t8('in the time between') %] [% fromdate.to_kivitendo %] - [% todate.to_kivitendo %])</td>
|
||
|
</tr>
|
||
|
</tbody></table>
|
||
|
</div>
|
||
|
|
||
|
<td>[%- L.button_tag("return \$('#detail_menu').dialog('close');", LxERP.t8('Close Details'), class => "submit") %]</td>
|
||
|
</div> <!-- col 1 -->
|
||
|
|
||
|
<div class="col"> <!-- col 2 -->
|
||
|
<div id="print_options" class="wrapper">
|
||
|
<form id="print_options_form">
|
||
|
[% print_options %]
|
||
|
<br>
|
||
|
[% L.button_tag('kivi.Part.print_from_showdetail(' _ part.id _ ')', LxERP.t8('Print')) %]
|
||
|
</form>
|
||
|
</div>
|
||
|
|
||
|
[% IF part.image && INSTANCE_CONF.get_parts_show_image %]
|
||
|
<div class="wrapper">
|
||
|
<a href="[% part.image | html %]" target="_blank"><img style="[% INSTANCE_CONF.get_parts_image_css %]" src="[% part.image | html %]"/></a>
|
||
|
</div>
|
||
|
[% END %]
|
||
|
</div> <!-- col 2 -->
|
||
| templates/webpages/part/showdetails.html | ||
|---|---|---|
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Description') %]</b></td><td colspan="3">[% part.description %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td style="background:wheat;"><b>[% LxERP.t8('Internal Notes') %]</b></td><td colspan="3" style="background:wheat;">[% part.intnotes %]</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Default Warehouse') %]</b></td><td>[% part.warehouse.description %]</td>
|
||
|
<td><b>[% LxERP.t8('Default Bin') %]</b></td><td>[% part.bin.description %]</td>
|
||
|
</tr>
|
||
| ... | ... | |
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Sum Amount') %]</b></td><td>[% LxERP.format_amount(sum, 2) %] [% part.unit %]</td>
|
||
|
<td rowspan="5">
|
||
|
[% file = part.default_partimage %]
|
||
|
[%- IF file && INSTANCE_CONF.get_parts_show_image %]
|
||
|
<img src="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]" alt="[% file.title %]" style="[% INSTANCE_CONF.get_parts_image_css %]">
|
||
|
[%- IF part.image && INSTANCE_CONF.get_parts_show_image %]
|
||
|
<a href="[% part.image | html %]" target="_blank"><img style="[% INSTANCE_CONF.get_parts_image_css %]" src="[% part.image | html %]"/></a>
|
||
|
[% END %]
|
||
|
</td>
|
||
|
<td rowspan="5">
|
||
|
[%- FOREACH file = part.get_files %]
|
||
|
<a href="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]">
|
||
|
<span id="[% "filename_" _ file.id %][%- IF file.version %]_[% file.version %][%- END %]">[% file.file_name %]</span></a><br><br>
|
||
|
[%- END %]
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
| ... | ... | |
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Ordered, but not delivered (purchase)') %]</b></td><td colspan="3">[% LxERP.format_amount(ordered, 2) %] [% part.unit %]</td></tr>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Reserved amount') %]</b></td><td colspan="3">[% LxERP.format_amount(part.stockqty - part.onhandqty, 2) %] [% part.unit %]</td></tr>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><b>[% LxERP.t8('Available amount') %]</b></td><td colspan="3">[% LxERP.format_amount(part.onhandqty, 2) %] [% part.unit %]</td></tr>
|
||
|
</tr>
|
||
Auch abrufbar als: Unified diff
DispositionManager: Popup Artikeldetails überarbeitet