Nick Clemens
41f2607563
Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
530 lines
13 KiB
Perl
Executable file
530 lines
13 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
|
|
# Copyright 2016 PTFS-Europe Ltd
|
|
#
|
|
# This file is part of Koha.
|
|
#
|
|
# Koha is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Koha is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
|
|
|
=head1 stockrotation.pl
|
|
|
|
Script to handle stockrotation. Including rotas, their associated stages
|
|
and items
|
|
|
|
=cut
|
|
|
|
use Modern::Perl;
|
|
use CGI;
|
|
|
|
use C4::Auth qw( get_template_and_user );
|
|
use C4::Context;
|
|
use C4::Output qw( output_html_with_http_headers );
|
|
|
|
use Koha::Libraries;
|
|
use Koha::StockRotationRotas;
|
|
use Koha::StockRotationItems;
|
|
use Koha::StockRotationStages;
|
|
use Koha::Item;
|
|
use Koha::Util::StockRotation qw( get_branches get_stages move_to_next_stage toggle_indemand remove_from_stage add_items_to_rota get_barcodes_status );
|
|
|
|
my $input = CGI->new;
|
|
|
|
unless (C4::Context->preference('StockRotation')) {
|
|
# redirect to Intranet home if self-check is not enabled
|
|
print $input->redirect("/cgi-bin/koha/mainpage.pl");
|
|
exit;
|
|
}
|
|
|
|
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
|
{
|
|
template_name => 'tools/stockrotation.tt',
|
|
query => $input,
|
|
type => 'intranet',
|
|
flagsrequired => {
|
|
tools => '*',
|
|
stockrotation => '*',
|
|
},
|
|
}
|
|
);
|
|
|
|
# Grab all passed data
|
|
# 'our' since Plack changes the scoping
|
|
# of 'my'
|
|
our %params = $input->Vars();
|
|
|
|
my $op = $params{op};
|
|
|
|
if (!defined $op) {
|
|
|
|
# No operation is supplied, we're just displaying the list of rotas
|
|
my $rotas = Koha::StockRotationRotas->search(
|
|
undef,
|
|
{
|
|
order_by => { -asc => 'title' }
|
|
}
|
|
)->as_list;
|
|
|
|
$template->param(
|
|
existing_rotas => $rotas,
|
|
no_op_set => 1
|
|
);
|
|
|
|
} elsif ($op eq 'create_edit_rota') {
|
|
|
|
# Edit an existing rota or define a new one
|
|
my $rota_id = $params{rota_id};
|
|
|
|
my $rota = {};
|
|
|
|
if (!defined $rota_id) {
|
|
|
|
# No ID supplied, we're creating a new rota
|
|
# Create a shell rota hashref
|
|
$rota = {
|
|
cyclical => 1
|
|
};
|
|
|
|
} else {
|
|
|
|
# ID supplied, we're editing an existing rota
|
|
$rota = Koha::StockRotationRotas->find($rota_id);
|
|
|
|
}
|
|
|
|
$template->param(
|
|
rota => $rota,
|
|
op => $op
|
|
);
|
|
|
|
} elsif ($op eq 'toggle_rota') {
|
|
|
|
# Find and update the active status of the rota
|
|
my $rota = Koha::StockRotationRotas->find($params{rota_id});
|
|
|
|
my $new_active = ($rota->active == 1) ? 0 : 1;
|
|
|
|
$rota->active($new_active)->store;
|
|
|
|
# Return to rotas page
|
|
print $input->redirect('stockrotation.pl');
|
|
|
|
} elsif ($op eq 'process_rota') {
|
|
|
|
# Get a hashref of the submitted rota data
|
|
my $rota = get_rota_from_form();
|
|
|
|
if (!process_rota($rota)) {
|
|
|
|
# The submitted rota was invalid
|
|
$template->param(
|
|
error => 'invalid_form',
|
|
rota => $rota,
|
|
op => 'create_edit_rota'
|
|
);
|
|
|
|
} else {
|
|
|
|
# All was well, return to the rotas list
|
|
print $input->redirect('stockrotation.pl');
|
|
|
|
}
|
|
|
|
} elsif ($op eq 'manage_stages') {
|
|
|
|
my $rota = Koha::StockRotationRotas->find($params{rota_id});
|
|
|
|
$template->param(
|
|
rota => $rota,
|
|
branches => get_branches(),
|
|
existing_stages => get_stages($rota),
|
|
rota_id => $params{rota_id},
|
|
op => $op
|
|
);
|
|
|
|
} elsif ($op eq 'create_edit_stage') {
|
|
|
|
# Edit an existing stage or define a new one
|
|
my $stage_id = $params{stage_id};
|
|
|
|
my $rota_id = $params{rota_id};
|
|
|
|
if (!defined $stage_id) {
|
|
|
|
# No ID supplied, we're creating a new stage
|
|
$template->param(
|
|
branches => get_branches(),
|
|
stage => {},
|
|
rota_id => $rota_id,
|
|
op => $op
|
|
);
|
|
|
|
} else {
|
|
|
|
# ID supplied, we're editing an existing stage
|
|
my $stage = Koha::StockRotationStages->find($stage_id);
|
|
|
|
$template->param(
|
|
branches => get_branches(),
|
|
stage => $stage,
|
|
rota_id => $stage->rota->rota_id,
|
|
op => $op
|
|
);
|
|
|
|
}
|
|
|
|
} elsif ($op eq 'confirm_remove_from_rota') {
|
|
|
|
# Get the stage we're deleting
|
|
$template->param(
|
|
op => $op,
|
|
rota_id => $params{rota_id},
|
|
stage_id => $params{stage_id},
|
|
item_id => $params{item_id}
|
|
);
|
|
|
|
} elsif ($op eq 'confirm_delete_stage') {
|
|
|
|
# Get the stage we're deleting
|
|
my $stage = Koha::StockRotationStages->find($params{stage_id});
|
|
|
|
$template->param(
|
|
op => $op,
|
|
stage => $stage
|
|
);
|
|
|
|
} elsif ($op eq 'delete_stage') {
|
|
|
|
# Get the stage we're deleting
|
|
my $stage = Koha::StockRotationStages->find($params{stage_id});
|
|
|
|
# Get the ID of the rota with which this stage is associated
|
|
# (so we can return to the "Manage stages" page after deletion)
|
|
my $rota_id = $stage->rota->rota_id;
|
|
|
|
$stage->delete;
|
|
|
|
# Return to the stages list
|
|
print $input->redirect("?op=manage_stages&rota_id=$rota_id");
|
|
|
|
} elsif ($op eq 'process_stage') {
|
|
|
|
# Get a hashref of the submitted stage data
|
|
my $stage = get_stage_from_form();
|
|
|
|
# The rota we're managing
|
|
my $rota_id = $params{rota_id};
|
|
|
|
if (!process_stage($stage, $rota_id)) {
|
|
|
|
# The submitted stage was invalid
|
|
# Get all branches
|
|
my $branches = get_branches();
|
|
|
|
$template->param(
|
|
error => 'invalid_form',
|
|
all_branches => $branches,
|
|
stage => $stage,
|
|
rota_id => $rota_id,
|
|
op => 'create_edit_stage'
|
|
);
|
|
|
|
} else {
|
|
|
|
# All was well, return to the stages list
|
|
print $input->redirect("?op=manage_stages&rota_id=$rota_id");
|
|
|
|
}
|
|
|
|
} elsif ($op eq 'manage_items') {
|
|
|
|
my $rota = Koha::StockRotationRotas->find($params{rota_id});
|
|
|
|
# Get all items on this rota, for each prefetch their
|
|
# stage and biblio objects
|
|
my $sritems = Koha::StockRotationItems->search(
|
|
{ 'stage.rota_id' => $params{rota_id} },
|
|
{
|
|
prefetch => {
|
|
stage => {
|
|
'stockrotationitems' => {
|
|
'itemnumber' => 'biblionumber'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
$template->param(
|
|
rota_id => $params{rota_id},
|
|
error => $params{error},
|
|
sritems => $sritems,
|
|
branches => get_branches(),
|
|
stages => get_stages($rota),
|
|
rota => $rota,
|
|
op => $op
|
|
);
|
|
|
|
} elsif ($op eq 'move_to_next_stage') {
|
|
|
|
move_to_next_stage($params{item_id}, $params{stage_id});
|
|
|
|
# Return to the items list
|
|
print $input->redirect("?op=manage_items&rota_id=" . $params{rota_id});
|
|
|
|
} elsif ($op eq 'toggle_in_demand') {
|
|
|
|
# Toggle the item's in_demand
|
|
toggle_indemand($params{item_id}, $params{stage_id});
|
|
|
|
# Return to the items list
|
|
print $input->redirect("?op=manage_items&rota_id=".$params{rota_id});
|
|
|
|
} elsif ($op eq 'remove_item_from_stage') {
|
|
|
|
# Remove the item from the stage
|
|
remove_from_stage($params{item_id}, $params{stage_id});
|
|
|
|
# Return to the items list
|
|
print $input->redirect("?op=manage_items&rota_id=".$params{rota_id});
|
|
|
|
} elsif ($op eq 'add_items_to_rota') {
|
|
|
|
# The item's barcode,
|
|
# which we may or may not have been passed
|
|
my $barcode = $params{barcode};
|
|
|
|
# The rota we're adding the item to
|
|
my $rota_id = $params{rota_id};
|
|
|
|
# The uploaded file filehandle,
|
|
# which we may or may not have been passed
|
|
my $barcode_file = $input->upload("barcodefile");
|
|
|
|
# We need to create an array of one or more barcodes to
|
|
# insert
|
|
my @barcodes = ();
|
|
|
|
# If the barcode input box was populated, use it
|
|
push @barcodes, $barcode if $barcode;
|
|
|
|
# Only parse the uploaded file if necessary
|
|
if ($barcode_file) {
|
|
|
|
# Call binmode on the filehandle as we want to set a
|
|
# UTF-8 layer on it
|
|
binmode($barcode_file, ":encoding(UTF-8)");
|
|
# Parse the file into an array of barcodes
|
|
while (my $barcode = <$barcode_file>) {
|
|
$barcode =~ s/\r/\n/g;
|
|
$barcode =~ s/\n+/\n/g;
|
|
my @data = split(/\n/, $barcode);
|
|
push @barcodes, @data;
|
|
}
|
|
|
|
}
|
|
|
|
# A hashref to hold the status of each barcode
|
|
my $barcode_status = {
|
|
ok => [],
|
|
on_other => [],
|
|
on_this => [],
|
|
not_found => []
|
|
};
|
|
|
|
# If we have something to work with, do it
|
|
get_barcodes_status($rota_id, \@barcodes, $barcode_status) if (@barcodes);
|
|
|
|
# Now we know the status of each barcode, add those that
|
|
# need it
|
|
if (scalar @{$barcode_status->{ok}} > 0) {
|
|
|
|
add_items_to_rota($rota_id, $barcode_status->{ok});
|
|
|
|
}
|
|
# If we were only passed one barcode and it was successfully
|
|
# added, redirect back to ourselves, we don't want to display
|
|
# a report, redirect also if we were passed no barcodes
|
|
if (
|
|
scalar @barcodes == 0 ||
|
|
(scalar @barcodes == 1 && scalar @{$barcode_status->{ok}} == 1)
|
|
) {
|
|
|
|
print $input->redirect("?op=manage_items&rota_id=$rota_id");
|
|
|
|
} else {
|
|
|
|
# Report on the outcome
|
|
$template->param(
|
|
barcode_status => $barcode_status,
|
|
rota_id => $rota_id,
|
|
op => $op
|
|
);
|
|
|
|
}
|
|
|
|
} elsif ($op eq 'move_items_to_rota') {
|
|
|
|
# The barcodes of the items we're moving
|
|
my @move = $input->param('move_item');
|
|
|
|
foreach my $item(@move) {
|
|
|
|
# The item we're moving
|
|
my $item = Koha::Items->find($item);
|
|
|
|
# Move it to the new rota
|
|
$item->add_to_rota($params{rota_id});
|
|
|
|
}
|
|
|
|
# Return to the items list
|
|
print $input->redirect("?op=manage_items&rota_id=".$params{rota_id});
|
|
|
|
}
|
|
|
|
output_html_with_http_headers $input, $cookie, $template->output;
|
|
|
|
sub get_rota_from_form {
|
|
|
|
return {
|
|
id => $params{id},
|
|
title => $params{title},
|
|
cyclical => $params{cyclical},
|
|
description => $params{description}
|
|
};
|
|
}
|
|
|
|
sub get_stage_from_form {
|
|
|
|
return {
|
|
stage_id => $params{stage_id},
|
|
branchcode => $params{branchcode},
|
|
duration => $params{duration}
|
|
};
|
|
}
|
|
|
|
sub process_rota {
|
|
|
|
my $sub_rota = shift;
|
|
|
|
# Fields we require
|
|
my @required = ('title','cyclical');
|
|
|
|
# Count of the number of required fields we have
|
|
my $valid = 0;
|
|
|
|
# Ensure we have everything we require
|
|
foreach my $req(@required) {
|
|
|
|
if (exists $sub_rota->{$req}) {
|
|
|
|
chomp(my $value = $sub_rota->{$req});
|
|
if (length $value > 0) {
|
|
$valid++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# If we don't have everything we need
|
|
return 0 if $valid != scalar @required;
|
|
|
|
# Passed validation
|
|
# Find the rota we're updating
|
|
my $rota = Koha::StockRotationRotas->find($sub_rota->{id});
|
|
|
|
if ($rota) {
|
|
|
|
$rota->title(
|
|
$sub_rota->{title}
|
|
)->cyclical(
|
|
$sub_rota->{cyclical}
|
|
)->description(
|
|
$sub_rota->{description}
|
|
)->store;
|
|
|
|
} else {
|
|
|
|
$rota = Koha::StockRotationRota->new({
|
|
title => $sub_rota->{title},
|
|
cyclical => $sub_rota->{cyclical},
|
|
active => 0,
|
|
description => $sub_rota->{description}
|
|
})->store;
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub process_stage {
|
|
|
|
my ($sub_stage, $rota_id) = @_;
|
|
|
|
# Fields we require
|
|
my @required = ('branchcode','duration');
|
|
|
|
# Count of the number of required fields we have
|
|
my $valid = 0;
|
|
|
|
# Ensure we have everything we require
|
|
foreach my $req(@required) {
|
|
|
|
if (exists $sub_stage->{$req}) {
|
|
|
|
chomp(my $value = $sub_stage->{$req});
|
|
if (length $value > 0) {
|
|
$valid++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# If we don't have everything we need
|
|
return 0 if $valid != scalar @required;
|
|
|
|
# Passed validation
|
|
# Find the stage we're updating
|
|
my $stage = Koha::StockRotationStages->find($sub_stage->{stage_id});
|
|
|
|
if ($stage) {
|
|
|
|
# Updating an existing stage
|
|
$stage->branchcode_id(
|
|
$sub_stage->{branchcode}
|
|
)->duration(
|
|
$sub_stage->{duration}
|
|
)->store;
|
|
|
|
} else {
|
|
|
|
# Creating a new stage
|
|
$stage = Koha::StockRotationStage->new({
|
|
branchcode_id => $sub_stage->{branchcode},
|
|
rota_id => $rota_id,
|
|
duration => $sub_stage->{duration}
|
|
})->store;
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head1 AUTHOR
|
|
|
|
Andrew Isherwood <andrew.isherwood@ptfs-europe.com>
|
|
|
|
=cut
|