Koha/acqui/addorder.pl
Julian Maurice b997250026 Bug 11844: Use additional fields for order lines
This patch allows to create additional fields for order lines.
Once created, these fields can be filled during order line creation or
modification.

If additional field is linked to a MARC field, there are two possible
scenario:
- MARC field mode = get: The field cannot be modified and its value is
  retrieved from the bibliographic record (current behaviour)
- MARC field mode = set: The field can be modified and its value is
  saved to the bibliographic record (new behaviour)

If additional field is linked to an authorised value category, then
authorised values are used. If not directly linked to an authorised
value category, but linked to a MARC field, a search for an AV category
is made on MARC default framework.

This patch doesn't display additional fields value anywhere (except in
order line creation/modification). Future patches will do that.

Test plan:
1/ Go to Acquisitions home
2/ In the left menu, click on "Add order line fields"
3/ Click on "New field" button
4/ Give the field a name (unique), no AV category and no MARC field.
5/ Save.
6/ Create 5 other fields:
   a/ no AV category, a MARC field not linked to AV category, MARC field
      mode = get
   b/ no AV category, a MARC field not linked to AV category, MARC field
      mode = set
   c/ no AV category, a MARC field linked to AV category, MARC field
      mode = get
   d/ no AV category, a MARC field linked to AV category, MARC field
      mode = set
   e/ an AV category, no MARC field
7/ Create everything you need to be able to create order lines
   (supplier, basket, ...)
8/ Create an order line. At bottom of the page, you should see your
   additional fields, with authorised values dropdrown list for fields
   (c), (d) and (e). Fields (a) and (c) should be disabled.
9/ Fill these fields with some data and save order line
10/ check that data was correctly saved into biblio for fields (b) and
    (d), but not for (a) and (c)
11/ modify the same order line, check that values you've filled are
    correctly retrieved and that values for (a) and (c) were correctly
    retrieved from the bibliographic record
12/ modify all values, save, and check biblio once again

Signed-off-by: Harold Dramer <harold.dramer@nyls.edu>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Michaela Sieber <michaela.sieber@kit.edu>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
2023-05-16 12:58:38 +02:00

457 lines
15 KiB
Perl
Executable file

#!/usr/bin/perl
#script to add an order into the system
#written 29/2/00 by chris@katipo.co.nz
# Copyright 2000-2002 Katipo Communications
#
# 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 NAME
addorder.pl
=head1 DESCRIPTION
this script allows to add an order.
It is called by :
=over
=item neworderempty.pl to add an order from an existing record or from nothing.
=item newordersuggestion.pl to add an order from an existing suggestion.
=back
=head1 CGI PARAMETERS
All of the cgi parameters below are related to the new order.
=over
=item C<ordernumber>
the number of this new order.
=item C<basketno>
the number of this new basket
=item C<booksellerid>
the bookseller the librarian has to pay.
=item C<existing>
=item C<title>
the title of the record ordered.
=item C<author>
the author of the record ordered.
=item C<copyrightdate>
the copyrightdate of the record ordered.
=item C<ISBN>
the ISBN of the record ordered.
=item C<format>
=item C<quantity>
the quantity to order.
=item C<listprice>
the price of this order.
=item C<uncertainprice>
uncertain price, can't close basket until prices of all orders are known.
=item C<branch>
the branch where this order will be received.
=item C<series>
=item C<notes>
Notes on this basket.
=item C<budget_id>
budget_id used to pay this order.
=item C<sort1> & C<sort2>
=item C<rrp>
=item C<ecost>
=item C<GST>
=item C<budget>
=item C<cost>
=item C<sub>
=item C<invoice>
the number of the invoice for this order.
=item C<publishercode>
=item C<suggestionid>
if it is an order from an existing suggestion : the id of this suggestion.
=item C<donation>
=back
=cut
use Modern::Perl;
use CGI qw ( -utf8 );
use JSON qw ( to_json encode_json );
use C4::Auth qw( get_template_and_user );
use C4::Acquisition qw( FillWithDefaultValues ModOrderUsers );
use C4::Suggestions qw( ModSuggestion );
use C4::Biblio qw(
AddBiblio
GetMarcFromKohaField
TransformHtmlToXml
TransformKohaToMarc
);
use C4::Budgets qw( GetBudget GetBudgetSpent GetBudgetOrdered );
use C4::Items qw( AddItemFromMarc );
use C4::Output qw( output_html_with_http_headers );
use C4::Log qw( logaction );
use Koha::Acquisition::Currencies qw( get_active );
use Koha::Acquisition::Orders;
use Koha::Acquisition::Baskets;
use C4::Barcodes;
use Koha::DateUtils qw( dt_from_string );
use Koha::AdditionalFields;
### "-------------------- addorder.pl ----------"
# FIXME: This needs to do actual error checking and possibly return user to the same form,
# not just blindly call C4 functions and print a redirect.
my $input = CGI->new;
my $use_ACQ_framework = $input->param('use_ACQ_framework');
# Check if order total amount exceed allowed budget
my $confirm_budget_exceeding = $input->param('confirm_budget_exceeding');
unless($confirm_budget_exceeding) {
my $budget_id = $input->param('budget_id');
my $total = $input->param('total');
my $budget = GetBudget($budget_id);
my $budget_spent = GetBudgetSpent($budget_id);
my $budget_ordered = GetBudgetOrdered($budget_id);
my $ordernumber = $input->param('ordernumber');
if ( $ordernumber ) {
# modifying an existing order so remove order price from $budget_ordered
my $order = Koha::Acquisition::Orders->find($ordernumber);
$budget_ordered = $budget_ordered - ( $order->ecost_tax_included * $order->quantity );
}
my $budget_used = $budget_spent + $budget_ordered;
my $budget_remaining = $budget->{budget_amount} - $budget_used;
my $budget_encumbrance = $budget->{budget_amount} * $budget->{budget_encumb} / 100;
my $budget_expenditure = $budget->{budget_expend};
if ( $total > $budget_remaining
|| ( ($budget_encumbrance+0) && ($budget_used + $total) > $budget_encumbrance)
|| ( ($budget_expenditure+0) && ($budget_used + $total) > $budget_expenditure) )
{
my ($template, $loggedinuser, $cookie) = get_template_and_user({
template_name => "acqui/addorder.tt",
query => $input,
type => "intranet",
flagsrequired => {acquisition => 'order_manage'},
});
my $url = $input->referer();
unless ( defined $url ) {
my $basketno = $input->param('basketno');
$url = "/cgi-bin/koha/acqui/basket.pl?basketno=$basketno";
}
my $vars = $input->Vars;
my @vars_loop;
foreach (keys %$vars) {
push @vars_loop, {
name => $_,
values => [ $input->multi_param($_) ],
};
}
if( ($budget_encumbrance+0) && ($budget_used + $total) > $budget_encumbrance
&& $total <= $budget_remaining)
{
$template->param(
encumbrance_exceeded => 1,
encumbrance => sprintf("%.2f", $budget->{'budget_encumb'}),
);
}
if( ($budget_expenditure+0) && ($budget_used + $total) > $budget_expenditure
&& $total <= $budget_remaining )
{
my $currency = Koha::Acquisition::Currencies->get_active;
$template->param(
expenditure_exceeded => 1,
expenditure => sprintf("%.2f", $budget_expenditure),
currency => ($currency) ? $currency->symbol : '',
);
}
if($total > $budget_remaining){
$template->param(budget_exceeded => 1);
}
$template->param(
not_enough_budget => 1,
referer => $url,
vars_loop => \@vars_loop,
);
output_html_with_http_headers $input, $cookie, $template->output;
exit;
}
}
# get_template_and_user used only to check auth & get user id
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "acqui/booksellers.tt",
query => $input,
type => "intranet",
flagsrequired => { acquisition => 'order_manage' },
}
);
# get CGI parameters
my $orderinfo = {
ordernumber => scalar $input->param('ordernumber'),
basketno => scalar $input->param('basketno'),
biblionumber => scalar $input->param('biblionumber'),
invoiceid => scalar $input->param('invoiceid'),
quantity => scalar $input->param('quantity'),
budget_id => scalar $input->param('budget_id'),
currency => scalar $input->param('currency'),
listprice => scalar $input->param('listprice'),
uncertainprice => scalar $input->param('uncertainprice'),
tax_rate_on_ordering => scalar $input->param('tax_rate'),
discount => scalar $input->param('discount'),
rrp => scalar $input->param('rrp'),
replacementprice => scalar $input->param('replacementprice'),
ecost => scalar $input->param('ecost'),
unitprice => scalar $input->param('unitprice'),
order_internalnote => scalar $input->param('order_internalnote'),
order_vendornote => scalar $input->param('order_vendornote'),
sort1 => scalar $input->param('sort1'),
sort2 => scalar $input->param('sort2'),
subscriptionid => scalar $input->param('subscriptionid'),
estimated_delivery_date => scalar $input->param('estimated_delivery_date'),
};
$orderinfo->{uncertainprice} ||= 0;
$orderinfo->{subscriptionid} ||= undef;
my $user = $input->remote_user;
my $basketno = $$orderinfo{basketno};
my $basket = Koha::Acquisition::Baskets->find($basketno);
# Order related fields we're going to log
my @log_order_fields = (
'quantity',
'listprice',
'unitprice',
'unitprice_tax_excluded',
'unitprice_tax_included',
'rrp',
'replacementprice',
'rrp_tax_excluded',
'rrp_tax_included',
'ecost',
'ecost_tax_excluded',
'ecost_tax_included',
'tax_rate_on_ordering'
);
# create, modify or delete biblio
# create if $quantity>0 and $existing='no'
# modify if $quantity>0 and $existing='yes'
if ( $basket->{is_standing} || $orderinfo->{quantity} ne '0' ) {
#TODO:check to see if biblio exists
unless ( $$orderinfo{biblionumber} ) {
my $record;
if ( $use_ACQ_framework ) {
my @tags = $input->multi_param('bib_tag');
my @subfields = $input->multi_param('bib_subfield');
my @field_values = $input->multi_param('bib_field_value');
my $xml = TransformHtmlToXml( \@tags, \@subfields, \@field_values );
$record=MARC::Record::new_from_xml($xml, 'UTF-8');
} else {
#if it doesn't create it
$record = TransformKohaToMarc(
{
"biblio.title" => $input->param('title') || '',
"biblio.author" => $input->param('author') || '',
"biblio.seriestitle" => $input->param('series') || '',
"biblioitems.isbn" => $input->param('isbn') || '',
"biblioitems.ean" => $input->param('ean') || '',
"biblioitems.publishercode" => $input->param('publishercode') || '',
"biblioitems.publicationyear" => $input->param('publicationyear') || '',
"biblio.copyrightdate" => $input->param('publicationyear') || '',
"biblioitems.itemtype" => $input->param('itemtype') || '',
"biblioitems.editionstatement"=> $input->param('editionstatement') || '',
}
);
}
C4::Acquisition::FillWithDefaultValues( $record );
# create the record in catalogue, with framework ''
my ($biblionumber,$bibitemnum) = AddBiblio($record,'');
$orderinfo->{biblionumber}=$biblionumber;
}
# change suggestion status if applicable
if ( my $suggestionid = $input->param('suggestionid') ) {
ModSuggestion(
{
suggestionid => $suggestionid,
biblionumber => $orderinfo->{biblionumber},
STATUS => 'ORDERED',
}
);
}
$orderinfo->{unitprice} = $orderinfo->{ecost} if not defined $orderinfo->{unitprice} or $orderinfo->{unitprice} eq '';
my $order;
my $log_action_name;
if ( $orderinfo->{ordernumber} ) {
$order = Koha::Acquisition::Orders->find($orderinfo->{ordernumber});
$order->set($orderinfo);
$log_action_name = 'MODIFY_ORDER';
} else {
$order = Koha::Acquisition::Order->new($orderinfo);
$log_action_name = 'CREATE_ORDER';
}
$order->populate_with_prices_for_ordering();
$order->store;
# Log the order creation
if (C4::Context->preference("AcquisitionLog")) {
my $infos = {};
foreach my $field(@log_order_fields) {
$infos->{$field} = $order->$field;
}
logaction(
'ACQUISITIONS',
$log_action_name,
$order->ordernumber,
encode_json($infos)
);
}
my $order_users_ids = $input->param('users_ids');
my @order_users = split( /:/, $order_users_ids );
ModOrderUsers( $order->ordernumber, @order_users );
# Retrieve and save additional fields values
my @additional_fields = Koha::AdditionalFields->search({ tablename => 'aqorders' })->as_list;
my @additional_field_values;
foreach my $af (@additional_fields) {
my $id = $af->id;
my $value = $input->param("additional_field_$id");
push @additional_field_values, {
id => $id,
value => $value,
};
}
$order->set_additional_fields(\@additional_field_values);
# now, add items if applicable
if ($basket->effective_create_items eq 'ordering') {
my @tags = $input->multi_param('tag');
my @subfields = $input->multi_param('subfield');
my @field_values = $input->multi_param('field_value');
my @serials = $input->multi_param('serial');
my @itemid = $input->multi_param('itemid');
#Rebuilding ALL the data for items into a hash
# parting them on $itemid.
my %itemhash;
my $countdistinct;
my $range=scalar(@itemid);
for (my $i=0; $i<$range; $i++){
unless ($itemhash{$itemid[$i]}){
$countdistinct++;
}
push @{$itemhash{$itemid[$i]}->{'tags'}},$tags[$i];
push @{$itemhash{$itemid[$i]}->{'subfields'}},$subfields[$i];
push @{$itemhash{$itemid[$i]}->{'field_values'}},$field_values[$i];
}
foreach my $item (keys %itemhash){
my $xml = TransformHtmlToXml( $itemhash{$item}->{'tags'},
$itemhash{$item}->{'subfields'},
$itemhash{$item}->{'field_values'},
undef,
undef,
'ITEM');
my $record=MARC::Record::new_from_xml($xml, 'UTF-8');
my ($barcodefield,$barcodesubfield) = GetMarcFromKohaField('items.barcode');
next unless ( defined $barcodefield && defined $barcodesubfield );
my $barcode = $record->subfield($barcodefield,$barcodesubfield) || '';
my $aBpref = C4::Context->preference('autoBarcode');
if( $barcode eq '' && $aBpref ne 'OFF'){
my $barcodeobj;
if ( $aBpref eq 'hbyymmincr'){
my ($homebranchfield,$homebranchsubfield) = GetMarcFromKohaField('items.homebranch');
my $homebranch = $record->subfield($homebranchfield,$homebranchsubfield);
$barcodeobj = C4::Barcodes->new($aBpref, $homebranch);
} else {
$barcodeobj = C4::Barcodes->new($aBpref);
}
$barcode = $barcodeobj->value();
$record->field($barcodefield)->delete_subfield( code => $barcodesubfield);
$record->field($barcodefield)->add_subfields($barcodesubfield => $barcode);
}
my ($biblionumber,$bibitemnum,$itemnumber) = AddItemFromMarc($record,$$orderinfo{biblionumber});
$order->add_item($itemnumber);
}
}
}
if (C4::Context->preference("AcquisitionLog") && $basketno) {
my $modified = Koha::Acquisition::Baskets->find( $basketno );
logaction(
'ACQUISITIONS',
'MODIFY_BASKET',
$basketno,
to_json($modified->unblessed)
);
}
my $booksellerid=$$orderinfo{booksellerid};
if (my $import_batch_id = $input->param('import_batch_id')) {
print $input->redirect("/cgi-bin/koha/acqui/addorderiso2709.pl?import_batch_id=$import_batch_id&basketno=$basketno&booksellerid=$booksellerid");
} elsif ( defined $orderinfo->{invoiceid} ) {
print $input->redirect("/cgi-bin/koha/acqui/parcel.pl?invoiceid=" . $orderinfo->{invoiceid});
} else {
print $input->redirect("/cgi-bin/koha/acqui/basket.pl?basketno=$basketno");
}