Revision dfe28d97
Von Werner Hahn vor mehr als 1 Jahr hinzugefügt
SL/Controller/DispositionsManager.pm | ||
---|---|---|
package SL::Controller::DispositionsManager;
|
||
|
||
|
||
use strict;
|
||
|
||
use parent qw(SL::Controller::Base);
|
||
|
||
use SL::DB::Part;
|
||
use SL::DB::PurchaseBasket;
|
||
use SL::Locale::String qw(t8);
|
||
|
||
sub action_list_parts {
|
||
my ( $self ) = @_;
|
||
|
||
my $query = <<SQL;
|
||
SELECT * FROM parts WHERE onhand <= rop AND rop != 0 AND id NOT IN( SELECT parts_id FROM purchase_basket) AND NOT obsolete
|
||
SQL
|
||
|
||
my $parts = SL::DB::Manager::Part->get_objects_from_sql( sql => $query );
|
||
$self->_setup_list_action_bar;
|
||
$self->render('dispositionsmanager/list_parts', title => t8('Parts short onhand'), PARTS => $parts);
|
||
|
||
|
||
}
|
||
|
||
sub action_add_to_purchase_basket{
|
||
my ( $self ) = @_;
|
||
|
||
my $parts_to_add = delete($::form->{id}) || [];
|
||
foreach my $id (@{ $parts_to_add }) {
|
||
my $part = SL::DB::Manager::Part->get_first( query => [ id => $id ] );
|
||
my $basket_part = SL::DB::PurchaseBasket->new(
|
||
parts_id => $part->id,
|
||
qty => $part->min_order_qty,
|
||
description => $part->description,
|
||
);
|
||
$basket_part->save;
|
||
}
|
||
$self->action_show_basket;
|
||
|
||
}
|
||
|
||
sub action_show_basket {
|
||
my ( $self ) = @_;
|
||
|
||
$::request->{layout}->add_javascripts('kivi.DispositionsManager.js');
|
||
my $basket = SL::DB::Manager::PurchaseBasket->get_all( query => [ cleared => 'F' ], with_objects => [ 'parts', 'parts.makemodels' ]);
|
||
$self->_setup_show_basket_action_bar;
|
||
$self->render('dispositionsmanager/show_purchase_basket', PARTS => $basket );
|
||
}
|
||
|
||
sub action_transfer_to_purchase_order {
|
||
my ( $self ) = @_;
|
||
|
||
|
||
}
|
||
|
||
sub _setup_list_action_bar {
|
||
my ($self) = @_;
|
||
for my $bar ($::request->layout->get('actionbar')) {
|
||
$bar->add(
|
||
action => [
|
||
t8('Action'),
|
||
submit => [ '#form', { action => "DispositionsManager/add_to_purchase_basket" } ],
|
||
tooltip => t8('Add to purchase basket'),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
sub _setup_show_basket_action_bar {
|
||
my ($self) = @_;
|
||
for my $bar ($::request->layout->get('actionbar')) {
|
||
$bar->add(
|
||
action => [
|
||
t8('Reload'),
|
||
submit => [ '#form', { action => "DispositionsManager/show_basket" } ],
|
||
],
|
||
action => [
|
||
t8('Action'),
|
||
submit => [ '#form', { action => "DispositionsManager/transfer_to_purchase_order" } ],
|
||
tooltip => t8('Create purchase order'),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
1;
|
||
|
||
__END__
|
||
|
||
=encoding utf-8
|
||
|
||
=head1 NAME
|
||
|
||
SL::Controller::DispositionsManager Controller to manage purchaseorders for parts
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This Controller shows a list of parts using the filter minimum stock (rop).
|
||
From this list it is possible to put parts in a purchase basket to order.
|
||
It's also possible to put parts from the parts edit form in the purchase basket.
|
||
|
||
From the purchase basket you can create a purchaseorder by using the filter vendor.
|
||
The quantity to order will be prefilled by the value min_qty_to_order from parts or
|
||
makemodel(vendor_parts) or default qty 1.
|
||
|
||
Tables:
|
||
|
||
=over 2
|
||
|
||
=item purchase_basket
|
||
|
||
=back
|
||
|
||
Depencies:
|
||
|
||
=over 2
|
||
|
||
=item parts
|
||
|
||
=item makemodels
|
||
|
||
|
||
=back
|
||
|
||
=head1 URL ACTIONS
|
||
|
||
=over 4
|
||
|
||
=item C<action_list_parts>
|
||
|
||
List the parts by the filter min stock (rop) and not in an open purchase order.
|
||
|
||
=item C<action_add_to_purchase_basket>
|
||
|
||
Adds one or more parts to the purchase basket.
|
||
|
||
=item C<action_show_basket>
|
||
|
||
Shows a list with parts wich are in the basket.
|
||
This List can be filtered by vendor. Then you can create a purchaseorder.
|
||
|
||
=item C<action_transfer_to_purchase_order>
|
||
|
||
Transfers the marked and by vendor filtered parts to a purchase order.
|
||
Deletes the entry in the purchasebasket.
|
||
|
||
=back
|
||
|
||
=head1 BUGS
|
||
|
||
None yet. :)
|
||
|
||
=head1 AUTHOR
|
||
|
||
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
|
||
|
||
=cut
|
SL/Controller/Part.pm | ||
---|---|---|
part_longdescription => '',
|
||
lastcost => 0,
|
||
sortorder => $position,
|
||
min_order_qty => '1',
|
||
) or die "Can't create MakeModel object";
|
||
|
||
my $row_as_html = $self->p->render('part/_makemodel_row',
|
||
... | ... | |
|
||
my $position = 0;
|
||
my $makemodels = delete($::form->{makemodels}) || [];
|
||
$main::lxdebug->dump(0, 'WH:MMFORM ', $makemodels);
|
||
foreach my $makemodel ( @{$makemodels} ) {
|
||
next unless $makemodel->{make};
|
||
$position++;
|
||
... | ... | |
my $position = 0;
|
||
my @makemodel_array = ();
|
||
my $makemodels = delete($::form->{makemodels}) || [];
|
||
$main::lxdebug->dump(0, 'WH:MM ', $makemodels);
|
||
|
||
foreach my $makemodel ( @{$makemodels} ) {
|
||
next unless $makemodel->{make};
|
||
... | ... | |
part_longdescription => $makemodel->{part_longdescription} || '',
|
||
lastcost => $::form->parse_amount(\%::myconfig, $makemodel->{lastcost_as_number} || 0),
|
||
sortorder => $position,
|
||
min_order_qty => $::form->parse_amount(\%::myconfig, $makemodel->{min_order_qty_as_number} || 0),
|
||
) or die "Can't create mm";
|
||
# $mm->id($makemodel->{id}) if $makemodel->{id};
|
||
push(@makemodel_array, $mm);
|
SL/DB/Helper/Mappings.pm | ||
---|---|---|
project_roles => 'project_role',
|
||
project_statuses => 'project_status',
|
||
project_types => 'project_type',
|
||
purchase_basket => 'purchase_basket',
|
||
reclamations => 'Reclamation',
|
||
reclamation_items => 'ReclamationItem',
|
||
reclamation_reasons => 'ReclamationReason',
|
SL/DB/Manager/PurchaseBasket.pm | ||
---|---|---|
# This file has been auto-generated only because it didn't exist.
|
||
# Feel free to modify it at will; it will not be overwritten automatically.
|
||
|
||
package SL::DB::Manager::PurchaseBasket;
|
||
|
||
use strict;
|
||
|
||
use parent qw(SL::DB::Helper::Manager);
|
||
|
||
sub object_class { 'SL::DB::PurchaseBasket' }
|
||
|
||
__PACKAGE__->make_manager_methods;
|
||
|
||
1;
|
SL/DB/MetaSetup/MakeModel.pm | ||
---|---|---|
lastcost => { type => 'numeric', precision => 15, scale => 5 },
|
||
lastupdate => { type => 'date' },
|
||
make => { type => 'integer' },
|
||
min_order_qty => { type => 'numeric', precision => 15, scale => 5 },
|
||
model => { type => 'text' },
|
||
mtime => { type => 'timestamp' },
|
||
part_description => { type => 'text' },
|
SL/DB/MetaSetup/PurchaseBasket.pm | ||
---|---|---|
# This file has been auto-generated. Do not modify it; it will be overwritten
|
||
# by rose_auto_create_model.pl automatically.
|
||
package SL::DB::PurchaseBasket;
|
||
|
||
use strict;
|
||
|
||
use parent qw(SL::DB::Object);
|
||
|
||
__PACKAGE__->meta->table('purchase_basket');
|
||
|
||
__PACKAGE__->meta->columns(
|
||
cleared => { type => 'boolean', default => 'false', not_null => 1 },
|
||
description => { type => 'text' },
|
||
id => { type => 'serial', not_null => 1 },
|
||
parts_id => { type => 'integer' },
|
||
qty => { type => 'numeric', precision => 15, scale => 5 },
|
||
);
|
||
|
||
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
|
||
|
||
__PACKAGE__->meta->foreign_keys(
|
||
parts => {
|
||
class => 'SL::DB::Part',
|
||
key_columns => { parts_id => 'id' },
|
||
},
|
||
);
|
||
|
||
1;
|
||
;
|
SL/DB/Part.pm | ||
---|---|---|
use SL::DB::MetaSetup::Part;
|
||
use SL::DB::Manager::Part;
|
||
use SL::DB::Chart;
|
||
use SL::DB::Vendor;
|
||
use SL::DB::Helper::AttrHTML;
|
||
use SL::DB::Helper::AttrSorted;
|
||
use SL::DB::Helper::TransNumberGenerator;
|
||
... | ... | |
return 1;
|
||
}
|
||
|
||
sub vendor_dropdown {
|
||
my ( $self ) = @_;
|
||
|
||
my @vendor_dd;
|
||
# $main::lxdebug->dump(0, 'WH:MakeModels ', $_[0]->makemodels);
|
||
|
||
foreach my $mm ( @{$_[0]->makemodels} ){
|
||
my $vendor = SL::DB::Manager::Vendor->get_first( where => [ id => $mm->make ] );
|
||
my @tmp = ({ title => $vendor->name, value => $vendor->{id} });
|
||
push @vendor_dd, @tmp;
|
||
}
|
||
return \@vendor_dd;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
SL/DB/PurchaseBasket.pm | ||
---|---|---|
# This file has been auto-generated only because it didn't exist.
|
||
# Feel free to modify it at will; it will not be overwritten automatically.
|
||
|
||
package SL::DB::PurchaseBasket;
|
||
|
||
use strict;
|
||
|
||
use SL::DB::MetaSetup::PurchaseBasket;
|
||
use SL::DB::Manager::PurchaseBasket;
|
||
|
||
__PACKAGE__->meta->initialize;
|
||
|
||
|
||
1;
|
js/kivi.DispositionsManager.js | ||
---|---|---|
namespace('kivi.DispositionsManager', function(ns) {
|
||
ns.sort_vendors = function() {
|
||
$("table tr").each(function(index) {
|
||
if ( index !== 0 ) {
|
||
$row = $(this);
|
||
// alert( $row.find('#vendor_id').val() + '!=' + $('#cv_id').val());
|
||
if( $row.find('#vendor_id').val() != $('#cv_id').val()) {
|
||
$row.remove();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
menus/user/10-dispositionsmanager.yaml | ||
---|---|---|
---
|
||
- parent: ap
|
||
id: ap_disp_manager
|
||
name: Dispositionsmanager
|
||
icon: rfq_add
|
||
order: 150
|
||
access: request_quotation_edit
|
||
- parent: ap_disp_manager
|
||
id: ap_disp_manager_onhand
|
||
name: List short onhand
|
||
order: 160
|
||
params:
|
||
action: DispositionsManager/list_parts
|
||
- parent: ap_disp_manager
|
||
id: ap_disp_manager_basket
|
||
name: Show purchase basket
|
||
order: 170
|
||
params:
|
||
action: DispositionsManager/show_basket
|
sql/Pg-upgrade2/purchase_basket.sql | ||
---|---|---|
-- @tag: purchase_basket
|
||
-- @description: Tabelle für den Dispostionsmanager
|
||
-- @depends: release_3_5_1
|
||
-- @ignore: 0
|
||
|
||
CREATE TABLE purchase_basket (
|
||
id SERIAL PRIMARY KEY,
|
||
parts_id INTEGER REFERENCES parts(id),
|
||
qty NUMERIC(15,5),
|
||
description text,
|
||
cleared BOOLEAN NOT NULL DEFAULT FALSE
|
||
);
|
||
|
||
ALTER TABLE parts ADD COLUMN min_order_qty NUMERIC(15,5);
|
||
ALTER TABLE makemodel ADD COLUMN min_order_qty NUMERIC(15,5);
|
templates/webpages/dispositionsmanager/list_parts.html | ||
---|---|---|
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
|
||
[% USE Dumper %]
|
||
[%- INCLUDE 'common/flash.html' %]
|
||
<h1>[% title %]</h1>
|
||
<hr>
|
||
<h2>[% 'Short onhand' | $T8 %]</h2>
|
||
<form id="form">
|
||
<table>
|
||
<thead>
|
||
<tr class="listheading">
|
||
<th>[% L.checkbox_tag('check_all') %][% 'Purchasebasket' | $T8 %] </th>
|
||
<th>[% 'Partnumber' | $T8 %] </th>
|
||
<th>[% 'Description' | $T8 %] </th>
|
||
<th>[% 'Onhand' | $T8 %] </th>
|
||
<th>[% 'Rop' | $T8 %] </th>
|
||
<th>[% 'Minimum order quantity' | $T8 %] </th>
|
||
</tr>
|
||
</thead>
|
||
[% FOREACH part = PARTS %]
|
||
[% IF !part.get_ordered_qty(part.id) %]
|
||
<tr class="listrow">
|
||
<td>[% IF part.makemodels.size %][% L.checkbox_tag('id[]', checked = '1', value=part.id) %][% ELSE %][% 'No Vendor' | $T8 %][% END %]</td>
|
||
<td>[% HTML.escape(part.partnumber) %] </td>
|
||
<td>[% HTML.escape(part.description) %]</td>
|
||
<td>[% part.onhand_as_number %] </td>
|
||
<td>[% part.rop_as_number %] </td>
|
||
<td>[% part.min_order_qty_as_number %] </td>
|
||
</tr>
|
||
[% END %]
|
||
[% END %]
|
||
</table>
|
||
</form>
|
||
<hr>
|
||
<h2>[% 'Short onhand Ordered' | $T8 %]</h2>
|
||
<table>
|
||
<thead>
|
||
<tr class="listheading">
|
||
<th>[% 'Partnumber' | $T8 %] </th>
|
||
<th>[% 'Description' | $T8 %] </th>
|
||
<th>[% 'onhand' | $T8 %] </th>
|
||
<th>[% 'rop' | $T8 %] </th>
|
||
<th>[% 'Ordered purchase' | $T8 %] </th>
|
||
</tr>
|
||
</thead>
|
||
[% FOREACH part = PARTS %]
|
||
[% IF part.get_ordered_qty(part.id) %]
|
||
<tr class="listrow">
|
||
<td>[% HTML.escape(part.partnumber) %] </td>
|
||
<td>[% HTML.escape(part.description) %] </td>
|
||
<td>[% part.onhand_as_number %] </td>
|
||
<td>[% part.rop_as_number %] </td>
|
||
<td>[% part.get_ordered_qty(part.id) %] </td>
|
||
</tr>
|
||
[% END %]
|
||
[% END %]
|
||
</table>
|
||
<script type="text/javascript">
|
||
<!--
|
||
|
||
kivi.DispositionsManager.sort_vendors();
|
||
$(function() {
|
||
alert('hallo9');
|
||
$('#check_all').checkall('INPUT[name^="id"]');
|
||
kivi.DispositionsManager.sort_vendors();
|
||
});
|
||
-->
|
||
</script>
|
templates/webpages/dispositionsmanager/show_purchase_basket.html | ||
---|---|---|
[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][% USE P %]
|
||
[% USE Dumper %]
|
||
[%- INCLUDE 'common/flash.html' %]
|
||
<h1>[% title %]</h1>
|
||
<hr>
|
||
[% # Dumper.dump_html(PARTS) %]
|
||
<form id="form">
|
||
[% P.customer_vendor.picker('vendor_id2', '', type='vendor', fat_set_item=1) %]<br>
|
||
<div>id from change: <span id='change3'></span></div>
|
||
[% L.hidden_tag('cv_id', '') %]
|
||
<table id="baskettable">
|
||
<thead>
|
||
<tr class="listheading">
|
||
<th>[% L.checkbox_tag('check_all') %][% 'Purchasebasket' | $T8 %] </th>
|
||
<th>[% 'Partnumber' | $T8 %] </th>
|
||
<th>[% 'Description' | $T8 %] </th>
|
||
<th>[% 'Onhand' | $T8 %] </th>
|
||
<th>[% 'Rop' | $T8 %] </th>
|
||
<th>[% 'Order quantity' | $T8 %] </th>
|
||
<th>[% 'Vendor' | $T8 %] </th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
[% FOREACH part = PARTS %]
|
||
[% SET select_size = part.parts.vendor_dropdown.size %]
|
||
[% IF !part.part.get_ordered_qty(part.id) %]
|
||
<tr class="listrow">
|
||
<td>[% L.checkbox_tag('id[]', checked = '1', value=part.id) %]</td>
|
||
<td>[% HTML.escape(part.parts.partnumber) %] </td>
|
||
<td>[% HTML.escape(part.parts.description) %]</td>
|
||
<td>[% part.parts.onhand_as_number %] </td>
|
||
<td>[% part.parts.rop_as_number %] </td>
|
||
<td>[% part.parts.min_order_qty %] </td>
|
||
<td>[% L.select_tag('vendor_id', part.parts.vendor_dropdown, value_key = 'value', title_key = 'title', default = part.parts.makemodels.item(0).make, size = select_size, style='width: 350px;' ) %]</td>
|
||
</tr>
|
||
[% END %]
|
||
[% END %]
|
||
</tbody>
|
||
</table>
|
||
</form>
|
||
<script type="text/javascript">
|
||
<!--
|
||
|
||
$('#vendor_id2').change(function() { $('#change3').html($('#vendor_id2').val()) })
|
||
$('#vendor_id2').on('set_item:CustomerVendorPicker', function(e,o) {
|
||
$('#cv_id').val(o.id)
|
||
kivi.DispositionsManager.sort_vendors();
|
||
})
|
||
$(function() {
|
||
$('#check_all').checkall('INPUT[name^="id"]');
|
||
});
|
||
-->
|
||
</script>
|
templates/webpages/part/_basic_data.html | ||
---|---|---|
</td>
|
||
</tr>
|
||
[%- END %]
|
||
<tr>
|
||
<th align="right" nowrap="true">[% 'Minimum order Quantity' | $T8 %]</th>
|
||
<td>[% L.input_tag("part.min_order_qty_as_number", SELF.part.min_order_qty_as_number, size=10, class="reformat_number numeric") %]</td>
|
||
</tr>
|
||
<tr>
|
||
<th align="right" nowrap="true">[% 'Verrechnungseinheit' | $T8 %]</th>
|
||
<td>[% L.input_tag("part.ve", SELF.part.ve, size=10) %]</td>
|
Auch abrufbar als: Unified diff
DispositionsManager: Prototyp ohne Auftrag erstellen