|
package SL::Controller::DispositionManager;
|
|
|
|
use strict;
|
|
|
|
use parent qw(SL::Controller::Base);
|
|
|
|
use SL::DB::Part;
|
|
use SL::DB::PurchaseBasketItem;
|
|
use SL::PriceSource;
|
|
use SL::Locale::String qw(t8);
|
|
use SL::Helper::Flash qw(flash);
|
|
use SL::DBUtils;
|
|
|
|
use Data::Dumper;
|
|
|
|
sub action_list_parts {
|
|
my ( $self ) = @_;
|
|
my $parts = $self->_get_parts;
|
|
$self->_setup_list_action_bar;
|
|
$self->render('disposition_manager/list_parts', title => t8('Parts short onhand'), PARTS => $parts);
|
|
}
|
|
|
|
sub action_add_to_purchase_basket{
|
|
my ( $self ) = @_;
|
|
|
|
my $parts_to_add = delete($::form->{ids}) || [];
|
|
foreach my $id (@{ $parts_to_add }) {
|
|
my $part = SL::DB::Manager::Part->find_by(id => $id) or die "Can't find part with id: $id\n";
|
|
my $basket_part = SL::DB::PurchaseBasketItem->new(
|
|
parts_id => $part->id,
|
|
qty => $part->ordersize, # was ist wenn order_size < (rop-onhand) ist? sollte dann nicht (rop-onhand) genommen werden?
|
|
)->save;
|
|
}
|
|
$self->action_show_basket;
|
|
|
|
}
|
|
|
|
sub action_show_basket {
|
|
my ( $self ) = @_;
|
|
|
|
$::request->{layout}->add_javascripts('kivi.DispositionManager.js', 'kivi.PartDetail.js');
|
|
my $basket_items = SL::DB::Manager::PurchaseBasketItem->get_all( query => [ cleared => 'F' ], with_objects => [ 'part', 'part.makemodels' ]);
|
|
$self->_setup_show_basket_action_bar;
|
|
$self->render('disposition_manager/show_purchase_basket', BASKET_ITEMS => $basket_items, title => "Purchase basket" );
|
|
}
|
|
|
|
sub action_show_vendor_items {
|
|
my ( $self ) = @_;
|
|
|
|
my $makemodels_parts = SL::DB::Manager::Part->get_all( query => [ 'makemodels.make' => $::form->{v_id}, 'makemodels.sortorder' => 1, '!id' => ['5599'], ], sort_by => 'onhand', with_objects => [ 'makemodels' ]);
|
|
$self->render('disposition_manager/_show_vendor_parts', { layout => 0 }, MAKEMODEL_ITEMS => $makemodels_parts);
|
|
}
|
|
|
|
sub action_transfer_to_purchase_order {
|
|
|
|
my ( $self ) = @_;
|
|
require SL::DB::Order;
|
|
require SL::DB::OrderItem;
|
|
require SL::DB::Vendor;
|
|
my @error_report;
|
|
|
|
unless (($::form->{ids} && scalar @{ $::form->{ids}}) || ( $::form->{vendor_part_ids} && scalar @{ $::form->{vendor_part_ids}})) {
|
|
die 'There are no items selected';
|
|
}
|
|
my $v_id = $::form->{vendor_ids}->[0] ;
|
|
|
|
my ($vendor, $employee);
|
|
$vendor = SL::DB::Manager::Vendor->find_by(id => $v_id) or die "Can't find vendor";
|
|
$employee = SL::DB::Manager::Employee->current or die "Can't find employee";
|
|
|
|
|
|
my $basket_items;
|
|
$basket_items = SL::DB::Manager::PurchaseBasketItem->get_all( query => [ id => \@{ $::form->{ids} } ] ) if ($::form->{ids} && scalar @{ $::form->{ids}});
|
|
|
|
my $vendor_items;
|
|
$vendor_items = SL::DB::Manager::Part->get_all( query => [ id => \@{ $::form->{vendor_part_ids} } ] ) if ($::form->{vendor_part_ids} && scalar @{ $::form->{vendor_part_ids}});
|
|
|
|
# create order first so we have a record for PriceSource
|
|
my $order = SL::DB::Order->new(
|
|
vendor_id => $vendor->id,
|
|
employee_id => $employee->id,
|
|
intnotes => $vendor->notes,
|
|
salesman_id => $employee->id,
|
|
payment_id => $vendor->payment_id,
|
|
delivery_term_id => $vendor->delivery_term_id,
|
|
taxzone_id => $vendor->taxzone_id,
|
|
currency_id => $vendor->currency_id,
|
|
transdate => DateTime->today_local
|
|
);
|
|
|
|
my $i = 0;
|
|
my @items;
|
|
|
|
if ($::form->{ids} && scalar @{ $::form->{ids}}) {
|
|
foreach my $basket_item ( @{ $basket_items } ) {
|
|
$i++;
|
|
|
|
my $current_order_item = SL::DB::OrderItem->new(
|
|
part => $basket_item->part,
|
|
qty => $basket_item->part->min_order_qty || 1,
|
|
unit => $basket_item->part->unit,
|
|
description => $basket_item->part->description,
|
|
longdescription => $basket_item->part->notes,
|
|
position => $i,
|
|
orderer_id => $basket_item->orderer->id,
|
|
price_factor_id => $basket_item->part->price_factor_id,
|
|
price_factor => $basket_item->part->price_factor_id ? $basket_item->part->price_factor->factor : '',
|
|
position => $i,
|
|
);
|
|
|
|
my $price_source = SL::PriceSource->new(record_item => $current_order_item, record => $order);
|
|
$current_order_item->sellprice($price_source->best_price->price);
|
|
$current_order_item->active_price_source($price_source->best_price->source);
|
|
push(@items, $current_order_item);
|
|
}
|
|
}
|
|
|
|
if ($::form->{vendor_part_ids} && scalar @{ $::form->{vendor_part_ids}}) {
|
|
foreach my $vendor_item ( @{ $vendor_items } ) {
|
|
$i++;
|
|
|
|
my $current_order_item = SL::DB::OrderItem->new(
|
|
part => $vendor_item,
|
|
qty => $vendor_item->ordersize || 1,
|
|
unit => $vendor_item->unit,
|
|
description => $vendor_item->description,
|
|
price_factor_id => $vendor_item->price_factor_id,
|
|
price_factor => $vendor_item->price_factor_id ? $vendor_item->price_factor->factor : '',
|
|
position => $i,
|
|
orderer_id => $employee->id,
|
|
);
|
|
|
|
my $price_source = SL::PriceSource->new(record_item => $current_order_item, record => $order);
|
|
$current_order_item->sellprice($price_source->best_price->price);
|
|
$current_order_item->active_price_source($price_source->best_price->source);
|
|
push(@items, $current_order_item);
|
|
}
|
|
}
|
|
|
|
$order->orderitems( [ @items ] );
|
|
|
|
$order->db->with_transaction( sub {
|
|
$order->calculate_prices_and_taxes;
|
|
$order->save;
|
|
|
|
my $snumbers = "ordernumber_" . $order->ordnumber;
|
|
SL::DB::History->new(
|
|
trans_id => $order->id,
|
|
snumbers => $snumbers,
|
|
employee_id => SL::DB::Manager::Employee->current->id,
|
|
addition => 'SAVED',
|
|
what_done => 'PurchaseBasket->Order',
|
|
)->save();
|
|
foreach my $item(@{ $order->orderitems }){
|
|
$item->parse_custom_variable_values->save;
|
|
$item->{custom_variables} = \@{ $item->cvars_by_config };
|
|
$item->save;
|
|
}
|
|
SL::DB::Manager::PurchaseBasketItem->delete_all( where => [ id => \@{ $::form->{ids} }]) if ($::form->{ids} && scalar @{ $::form->{ids}});
|
|
return 1;
|
|
}) || die "error: " . $order->db->error;
|
|
|
|
my $user_prefs_doc = SL::Helper::UserPreferences->new(
|
|
namespace => 'DefaultOrderController',
|
|
);
|
|
my $doc_val = $::instance_conf->get_feature_experimental_order ? 'new' : 'old';
|
|
$doc_val = $user_prefs_doc->get('default_order_controller') if ($user_prefs_doc);
|
|
if ( $doc_val eq 'old') {
|
|
$self->redirect_to(
|
|
controller => 'oe.pl',
|
|
action => 'edit',
|
|
type => 'purchase_order',
|
|
vc => 'vendor',
|
|
id => $order->id,
|
|
);
|
|
} else {
|
|
$self->redirect_to(
|
|
controller => 'Order',
|
|
action => 'edit',
|
|
type => 'purchase_order',
|
|
vc => 'vendor',
|
|
id => $order->id,
|
|
);
|
|
}
|
|
}
|
|
|
|
sub _get_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_items )
|
|
AND NOT obsolete
|
|
ORDER BY partnumber
|
|
SQL
|
|
|
|
return SL::DB::Manager::Part->get_objects_from_sql( sql => $query );
|
|
};
|
|
|
|
|
|
sub _setup_list_action_bar {
|
|
my ($self) = @_;
|
|
for my $bar ($::request->layout->get('actionbar')) {
|
|
$bar->add(
|
|
action => [
|
|
t8('Action'),
|
|
submit => [ '#form', { action => "DispositionManager/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'),
|
|
link => $self->url_for(controller => 'DispositionManager', action => 'show_basket'),
|
|
],
|
|
action => [
|
|
t8('Action'),
|
|
call => [ 'kivi.DispositionManager.create_order' ],
|
|
tooltip => t8('Create purchase order'),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
1;
|
|
|
|
__END__
|
|
|
|
=encoding utf-8
|
|
|
|
=head1 NAME
|
|
|
|
SL::Controller::DispositionManager Controller to manage purchase orders 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 purchase order 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 to qty 1.
|
|
|
|
Tables:
|
|
|
|
=over 2
|
|
|
|
=item purchase_basket
|
|
|
|
=back
|
|
|
|
Dependencies:
|
|
|
|
=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 which are in the basket.
|
|
This list can be filtered by vendor. Then you can create a purchase order.
|
|
When filtered by vendor, a table with the parts from the vendor of the purchase basket and
|
|
a table with all parts from the vendor will be shown. From there you can mark
|
|
the parts and create an order
|
|
|
|
=item C<action_transfer_to_purchase_order>
|
|
|
|
Transfers the marked and by vendor filtered parts to a purchase order.
|
|
Deletes the entry in the purchase basket.
|
|
|
|
=back
|
|
|
|
=head1 BUGS
|
|
|
|
None yet. :)
|
|
|
|
=head1 AUTHOR
|
|
|
|
W. Hahn E<lt>wh@futureworldsearch.netE<gt>
|
|
|
|
=cut
|