@@ -, +, @@ - modification of database structure : new column "deletedbiblionumber" in aqorders - modification of GetOrder, GetOrders and GetCancelledOrders in C4::Acquisition - modification of DelBiblio in C4::Biblio - modification of the 2 templates - add UT for DelBiblio - add UT for GetOrder and partially to NewOrder - adding UT for GetOrders and GetCancelledOrders - maybe improve template in receipt page - doing the same for invoice - create a basket with 5 orders using records A,B,C,D (you can use existing records or create new ones, it does not matter) - delete 2 orders A & B, but keep the records - in the catalogue, suppress record A (used by a cancelled order) & D (used by an active order) - refresh the basket page : you should see the suppressed orders in Cancelled Orders block, with readable title and authors of deleted records, and a note (Deleted record) - click on "Modifiy" for order D. You should see the title, author, publisher, date... without the link [Edit Record] but with a message (Deleted record, non editable) - click on "Modify" for record C. You should have [Edit record] link - create an order E. - delete order E, and the record (link 'delete order and record') - refresh the basket. you should see the order in the Cancelled Orders, with a readable title and author - launch unit tests : --- C4/Acquisition.pm | 345 ++++++++++++++++++-- C4/Biblio.pm | 31 +- acqui/basket.pl | 3 +- acqui/neworderempty.pl | 1 + installer/data/mysql/kohastructure.sql | 2 + installer/data/mysql/updatedatabase.pl | 6 + .../intranet-tmpl/prog/en/modules/acqui/basket.tt | 11 +- .../prog/en/modules/acqui/neworderempty.tt | 43 +-- t/db_dependent/Acquisition.t | 310 +++++++++++++++++- t/db_dependent/Biblio.t | 136 +++++++- 10 files changed, 825 insertions(+), 63 deletions(-) --- a/C4/Acquisition.pm +++ a/C4/Acquisition.pm @@ -921,7 +921,7 @@ sub GetPendingOrders { @orders = &GetOrders($basketnumber, $orderby); -Looks up the pending (non-cancelled) orders with the given basket +Looks up non-cancelled orders (pending and received) with the given basket number. If C<$booksellerID> is non-empty, only orders from that seller are returned. @@ -929,29 +929,130 @@ return : C<&basket> returns a two-element array. C<@orders> is an array of references-to-hash, whose keys are the fields from the aqorders, biblio, and biblioitems tables in the Koha database. +If the record have been suppressed, its biblionumber is only returned in deletedbiblionumber column. =cut sub GetOrders { my ( $basketno, $orderby ) = @_; my $dbh = C4::Context->dbh; + # get all the fields of biblio, and all of biblioitems, except marc (marc blob) and timestamp + # timestamp is used in biblio and in aqorders, so rename biblio.timestamp into biblio_timestamp + # notes are used in biblio, biblioitems and aqorders. Rename biblio.notes and biblio into biblio_notes and biblioitems_notes my $query =" - SELECT biblio.*,biblioitems.*, + SELECT all_biblio.*, + all_biblioitems.*, aqorders.*, aqbudgets.*, - biblio.title, aqorders_transfers.ordernumber_from AS transferred_from, aqorders_transfers.timestamp AS transferred_from_timestamp FROM aqorders - LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id - LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber - LEFT JOIN biblioitems ON biblioitems.biblionumber =biblio.biblionumber + LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id + LEFT JOIN ( + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM biblio + UNION ALL + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM deletedbiblio + ) AS all_biblio ON ((all_biblio.biblionumber=aqorders.biblionumber) OR (all_biblio.biblionumber=aqorders.deletedbiblionumber)) + LEFT JOIN ( + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM biblioitems + UNION ALL + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM deletedbiblioitems + ) AS all_biblioitems ON ((all_biblioitems.biblionumber=aqorders.biblionumber) OR (all_biblioitems.biblionumber=aqorders.deletedbiblionumber)) LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_to = aqorders.ordernumber WHERE basketno=? AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00') "; - - $orderby = "biblioitems.publishercode,biblio.title" unless $orderby; + $orderby = "all_biblioitems.publishercode,all_biblio.title" unless $orderby; $query .= " ORDER BY $orderby"; my $sth = $dbh->prepare($query); $sth->execute($basketno); @@ -1005,19 +1106,121 @@ Looks up an order by order number. Returns a reference-to-hash describing the order. The keys of C<$order> are fields from the biblio, biblioitems, aqorders tables of the Koha database. +If the record have been suppressed, its biblionumber is only returned in deletedbiblionumber column. =cut sub GetOrder { my ($ordernumber) = @_; my $dbh = C4::Context->dbh; + # get all the fields of biblio, and all of biblioitems, except marc (marc blob) and timestamp + # timestamp is used in biblio and in aqorders, so rename biblio.timestamp into biblio_timestamp + # notes are used in biblio, biblioitems and aqorders. Rename biblio.notes and biblio into biblio_notes and biblioitems_notes my $query = " - SELECT biblioitems.*, biblio.*, aqorders.* + SELECT all_biblio.*, all_biblioitems.*, + aqorders.* FROM aqorders - LEFT JOIN biblio on biblio.biblionumber=aqorders.biblionumber - LEFT JOIN biblioitems on biblioitems.biblionumber=aqorders.biblionumber + LEFT JOIN ( + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM biblio + UNION ALL + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM deletedbiblio + ) AS all_biblio ON ((all_biblio.biblionumber=aqorders.biblionumber) OR (all_biblio.biblionumber=aqorders.deletedbiblionumber)) + LEFT JOIN ( + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM biblioitems + UNION ALL + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM deletedbiblioitems + ) AS all_biblioitems ON ((all_biblioitems.biblionumber=aqorders.biblionumber) OR (all_biblioitems.biblionumber=aqorders.deletedbiblionumber)) WHERE aqorders.ordernumber=? - "; my $sth= $dbh->prepare($query); $sth->execute($ordernumber); @@ -1026,6 +1229,7 @@ sub GetOrder { return $data; } + =head3 GetLastOrderNotReceivedFromSubscriptionid $order = &GetLastOrderNotReceivedFromSubscriptionid($subscriptionid); @@ -1113,8 +1317,7 @@ Else, the upcoming July 1st is used. =item defaults entrydate to Now -The following keys are used: "biblionumber", "title", "basketno", "quantity", "notes", "rrp", "ecost", "gstrate", "unitprice", "subscription", "sort1", "sort2", "booksellerinvoicenumber", "listprice", "budgetdate", "purchaseordernumber", "branchcode", "booksellerinvoicenumber", "budget_id". - +The following keys are used: "biblionumber", "basketno", "quantity", "notes", "rrp", "ecost", "gstrate", "unitprice", "subscription", "sort1", "sort2", "booksellerinvoicenumber", "listprice", "budgetdate", "purchaseordernumber", "branchcode", "booksellerinvoicenumber", "budget_id". =back =cut @@ -1257,7 +1460,8 @@ sub ModItemOrder { my @orders = GetCancelledOrders($basketno, $orderby); -Returns cancelled orders for a basket +Returns cancelled orders for a basket. +If the record have been suppressed, its biblionumber is only retuned in deletedbiblionumber column. =cut @@ -1269,17 +1473,115 @@ sub GetCancelledOrders { my $dbh = C4::Context->dbh; my $query = " SELECT - biblio.*, - biblioitems.*, + all_biblio.*, + all_biblioitems.*, aqorders.*, aqbudgets.*, aqorders_transfers.ordernumber_to AS transferred_to, aqorders_transfers.timestamp AS transferred_to_timestamp FROM aqorders - LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id - LEFT JOIN biblio ON biblio.biblionumber = aqorders.biblionumber - LEFT JOIN biblioitems ON biblioitems.biblionumber = biblio.biblionumber - LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_from = aqorders.ordernumber + LEFT JOIN aqbudgets ON aqbudgets.budget_id = aqorders.budget_id + LEFT JOIN ( + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM biblio + UNION ALL + SELECT biblionumber, + frameworkcode, + author, + title, + unititle, + notes AS biblio_notes, + serial, + seriestitle, + copyrightdate, + timestamp AS biblio_timestamp, + datecreated, + abstract + FROM deletedbiblio + ) AS all_biblio ON ((all_biblio.biblionumber=aqorders.biblionumber) OR (all_biblio.biblionumber=aqorders.deletedbiblionumber)) + LEFT JOIN ( + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM biblioitems + UNION ALL + SELECT biblionumber, + biblioitemnumber, + volume, + number, + itemtype, + isbn, + issn, + ean, + publicationyear, + publishercode, + volumedate, + volumedesc, + collectiontitle, + collectionissn, + collectionvolume, + editionstatement, + editionresponsibility, + illus, + pages, + notes AS biblioitems_notes, + size, + place, + lccn, + marc, + url, + cn_source, + cn_class, + cn_item, + cn_suffix, + cn_sort, + agerestriction, + totalissues, + marcxml + FROM deletedbiblioitems + ) AS all_biblioitems ON ((all_biblioitems.biblionumber=aqorders.biblionumber) OR (all_biblioitems.biblionumber=aqorders.deletedbiblionumber)) + LEFT JOIN aqorders_transfers ON aqorders_transfers.ordernumber_from = aqorders.ordernumber WHERE basketno = ? AND (datecancellationprinted IS NOT NULL AND datecancellationprinted <> '0000-00-00') @@ -1295,7 +1597,6 @@ sub GetCancelledOrders { return @$results; } - #------------------------------------------------------------# =head3 ModReceiveOrder --- a/C4/Biblio.pm +++ a/C4/Biblio.pm @@ -402,10 +402,16 @@ sub ModBiblioframework { my $error = &DelBiblio($biblionumber); -Exported function (core API) for deleting a biblio in koha. -Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items) -Also backs it up to deleted* tables -Checks to make sure there are not issues on any of the items +Exported function (core API) for deleting a biblio in Koha. +Action : +It the record has an item, do not delete the record, and return an error message. +If the record has no item, +- deletes biblio record from Zebra and Koha tables (biblio,biblioitems), +- backs Koha tables it up to deleted* tables, +- delete attached suscriptions +- if the record is used in an order, move the biblionumber from aqorders.biblionumber to aqorders.deletedbiblionumber +- record the action in logs + return: C<$error> : undef unless an error occurs @@ -441,15 +447,20 @@ sub DelBiblio { C4::Reserves::CancelReserve({ reserve_id => $res->{'reserve_id'} }); } + # Get all orders using this record. Must be done before deleting the record to be able to find orders to update after deletion + require C4::Acquisition; + my @orders = C4::Acquisition::GetOrdersByBiblionumber ($biblionumber); + # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio # for at least 2 reasons : # - if something goes wrong, the biblio may be deleted from Koha but not from zebra # and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem) ModZebra( $biblionumber, "recordDelete", "biblioserver" ); - # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems + # delete the record from biblioitems table and save it in deletedbiblioitems,deleteditems $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?"); $sth->execute($biblionumber); + #FIXME : the loop is probably unneeded while ( my $biblioitemnumber = $sth->fetchrow ) { # delete this biblioitem @@ -462,7 +473,17 @@ sub DelBiblio { # delete cascade will prevent deletedbiblioitems rows # from being generated by _koha_delete_biblioitems $error = _koha_delete_biblio( $dbh, $biblionumber ); + return $error if $error; + #If the record is used in an order, move the biblionumber from aqorders.biblionumber to aqorders.deletedbiblionumber + if (scalar @orders > 0) { + for my $myorder (@orders) { + $sth = $dbh->prepare("UPDATE aqorders + SET deletedbiblionumber = ? + WHERE ordernumber=?"); + $sth->execute($biblionumber,$myorder->{ordernumber}); + } + } logaction( "CATALOGUING", "DELETE", $biblionumber, "" ) if C4::Context->preference("CataloguingLog"); return; --- a/acqui/basket.pl +++ a/acqui/basket.pl @@ -383,7 +383,7 @@ sub get_order_infos { $line{'title'} .= " / $seriestitle" if $seriestitle; $line{'title'} .= " / $volume" if $volume; } else { - $line{'title'} = "Deleted bibliographic notice, can't find title."; + $line{'title'} = "Can't find title."; } my $biblionumber = $order->{'biblionumber'}; @@ -432,7 +432,6 @@ sub get_order_infos { }; } } - return \%line; } --- a/acqui/neworderempty.pl +++ a/acqui/neworderempty.pl @@ -377,6 +377,7 @@ $template->param( surnamesuggestedby => $suggestion->{surnamesuggestedby}, firstnamesuggestedby => $suggestion->{firstnamesuggestedby}, biblionumber => $biblionumber, + deletedbiblionumber => $data->{'deletedbiblionumber'}, uncertainprice => $data->{'uncertainprice'}, authorisedbyname => $borrower->{'firstname'} . " " . $borrower->{'surname'}, discount_2dp => sprintf( "%.2f", $bookseller->{'discount'} ) , # for display --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -2904,6 +2904,7 @@ DROP TABLE IF EXISTS `aqorders`; CREATE TABLE `aqorders` ( -- information related to the basket line items `ordernumber` int(11) NOT NULL auto_increment, -- primary key and unique identifier assigned by Koha to each line `biblionumber` int(11) default NULL, -- links the order to the biblio being ordered (biblio.biblionumber) + `deletedbiblionumber` int(11) default NULL, -- links the order to the deletedbiblio being ordered (deletedbiblio.biblionumber) `entrydate` date default NULL, -- the date the bib was added to the basket `quantity` smallint(6) default NULL, -- the quantity ordered `currency` varchar(3) default NULL, -- the currency used for the purchase @@ -2944,6 +2945,7 @@ CREATE TABLE `aqorders` ( -- information related to the basket line items CONSTRAINT `aqorders_ibfk_1` FOREIGN KEY (`basketno`) REFERENCES `aqbasket` (`basketno`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `aqorders_ibfk_2` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT aqorders_ibfk_3 FOREIGN KEY (invoiceid) REFERENCES aqinvoices (invoiceid) ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT aqorders_ibfk_4 FOREIGN KEY (deletedbiblionumber) REFERENCES deletedbiblio (biblionumber) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `aqorders_subscriptionid` FOREIGN KEY (`subscriptionid`) REFERENCES `subscription` (`subscriptionid`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -7303,6 +7303,12 @@ if ( CheckVersion($DBversion) ) { }); print "Upgrade to $DBversion done (Bug 10565 - Add a 'Patron List' feature for storing and manipulating collections of patrons)\n"; + +$DBversion = "3.13.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do("ALTER TABLE aqorders ADD COLUMN deletedbiblionumber INT(11) DEFAULT NULL AFTER biblionumber;"); + $dbh->do("ALTER TABLE aqorders ADD CONSTRAINT `aqorders_ibfk_4` FOREIGN KEY (`deletedbiblionumber`) REFERENCES `deletedbiblio` (`biblionumber`) ON DELETE SET NULL ON UPDATE CASCADE;"); + print "Upgrade to $DBversion done \n"; SetVersion($DBversion); } --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt @@ -339,8 +339,13 @@ [% IF (books_loo.biblionumber) %] [% books_loo.title |html %] by [% books_loo.author %]
+ [% ELSIF (books_loo.deletedbiblionumber) %] + [% books_loo.title |html %] by [% books_loo.author %] +
+ (Deleted record) +
[% ELSE %] - Deleted bibliographic record, can't find title
+ Can't find title
[% END %] [% IF ( books_loo.isbn ) %] - [% books_loo.isbn %][% END %] [% IF ( books_loo.issn ) %] - [% books_loo.issn %][% END %] @@ -453,10 +458,10 @@

[% IF ( order.order_received ) %] (rcvd)[% END %] - [% IF (order.biblionumber) %] + [% IF (order.biblionumber)||(order.deletedbiblionumber) %] [% order.title |html %] by [% order.author %]
[% ELSE %] - Deleted bibliographic record, can't find title
+ Can't find title
[% END %] [% IF ( order.notes ) %] [% order.notes %][% END %] [% IF ( order.isbn ) %] - [% order.isbn %][% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt @@ -214,7 +214,9 @@ $(document).ready(function() Catalog details [% IF ( biblionumber ) %] Edit record - [% END %] + [% ELSIF (deletedbiblionumber) %] + (Deleted record, not editable) + [% END %] [% UNLESS ( existing ) %] @@ -234,26 +236,26 @@ $(document).ready(function() [% END %]

  1. - [% IF ( biblionumber ) %] - Title + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Title: [% title |html %] - [% ELSE %] + [% ELSE %] [% END %]
  2. - [% IF ( biblionumber ) %] - Author: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Author: [% author %] - [% ELSE %] + [% ELSE %] [% END %]
  3. - [% IF ( biblionumber ) %] - Publisher: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Publisher: [% publishercode %] [% ELSE %] @@ -261,18 +263,17 @@ $(document).ready(function() [% END %]
  4. - [% IF ( biblionumber ) %] - Edition: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Edition: [% editionstatement %] - [% ELSE %] [% END %]
  5. - [% IF ( biblionumber ) %] - Publication year: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Publication year: [% publicationyear %] [% ELSE %] @@ -280,8 +281,8 @@ $(document).ready(function() [% END %]
  6. - [% IF ( biblionumber ) %] - ISBN: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + ISBN: [% isbn %] [% ELSE %] @@ -290,8 +291,8 @@ $(document).ready(function()
  7. [% IF (UNIMARC) %]
  8. - [% IF ( biblionumber ) %] - EAN: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + EAN: [% ean %] [% ELSE %] @@ -300,15 +301,15 @@ $(document).ready(function()
  9. [% END %]
  10. - [% IF ( biblionumber ) %] - Series: + [% IF ( biblionumber )||( deletedbiblionumber ) %] + Series: [% seriestitle %] [% ELSE %] [% END %]
  11. - [% UNLESS ( biblionumber ) %] + [% UNLESS (( biblionumber )||( deletedbiblionumber )) %] [% IF ( itemtypeloop ) %]
  12. Item type: --- a/t/db_dependent/Acquisition.t +++ a/t/db_dependent/Acquisition.t @@ -8,7 +8,7 @@ use POSIX qw(strftime); use C4::Bookseller qw( GetBookSellerFromId ); -use Test::More tests => 41; +use Test::More tests => 234; BEGIN { use_ok('C4::Acquisition'); @@ -48,17 +48,80 @@ my $budgetid = C4::Budgets::AddBudget( ); my $budget = C4::Budgets::GetBudget( $budgetid ); -my ($ordernumber1, $ordernumber2, $ordernumber3); +# +# FUNCTIONS ABOUT ORDERS + AddClaim +# TransferOrder, OrderFromSubscription and GetOrdersByBiblionumber : tested in separated UT +# + +# +# Test NewOrder +# + +# Add a branch +my $b1 = { + add => 1, + branchcode => 'BRA', + branchname => 'BranchA', + branchaddress1 => 'adr1A', + branchaddress2 => 'adr2A', + branchaddress3 => 'adr3A', + branchzip => 'zipA', + branchcity => 'cityA', + branchstate => 'stateA', + branchcountry => 'countryA', + branchphone => 'phoneA', + branchfax => 'faxA', + branchemail => 'emailA', + branchurl => 'urlA', + branchip => 'ipA', + branchprinter => undef, + branchnotes => 'noteA', + opac_info => 'opacA' +}; +&C4::Branch::ModBranch($b1); + +my ($mandatoryparams, $return_error,$basketnum,$ordernumber1, $ordernumber2, $ordernumber3); my ($biblionumber1, $biblioitemnumber1) = AddBiblio(MARC::Record->new, ''); my ($biblionumber2, $biblioitemnumber2) = AddBiblio(MARC::Record->new, ''); -( undef, $ordernumber1 ) = C4::Acquisition::NewOrder( - { + +# returns undef and croaks if basketno, quantity, biblionumber or budget_id is missing +eval {($basketnum, $ordernumber1 ) = C4::Acquisition::NewOrder()}; +$return_error = $@; +ok ((!(defined $basketnum || defined $ordernumber1)) && (defined $return_error),"NewOrder with no params returns undef and croaks"); + +$mandatoryparams = { basketno => $basketno, quantity => 24, biblionumber => $biblionumber1, budget_id => $budget->{budget_id}, - } -); + }; +my @mandatoryparams_keys = keys %$mandatoryparams; +foreach my $mandatoryparams_key (@mandatoryparams_keys) { + my %test_missing_mandatoryparams = %$mandatoryparams; + delete $test_missing_mandatoryparams {$mandatoryparams_key}; + eval {($basketnum, $ordernumber1 ) = C4::Acquisition::NewOrder(\%test_missing_mandatoryparams)}; + $return_error = $@; + my $expected_error = "Mandatory parameter $mandatoryparams_key missing"; + ok ((!(defined $basketnum || defined $ordernumber1)) && ( index ($return_error, $expected_error) >=0 ),"NewOrder with no $mandatoryparams_key returns undef and croaks with expected error message"); +} + +# FIXME to do : test the other features of NewOrder + +my $order1_content = { + basketno => $basketno, + quantity => 2, + biblionumber => $biblionumber1, + budget_id => $budget->{budget_id}, + listprice=>50.121111, + ecost => 38.15, + rrp => 40.15, + discount =>5.1111, + branchcode=>"BRA", + uncertainprice=>0, + notes=>"ordernotes", + gstrate=>0.0515 + }; +( undef, $ordernumber1 ) = C4::Acquisition::NewOrder($order1_content); ( undef, $ordernumber2 ) = C4::Acquisition::NewOrder( { @@ -80,10 +143,203 @@ my ($biblionumber2, $biblioitemnumber2) = AddBiblio(MARC::Record->new, ''); } ); +# +# Test DelOrder +# + +# +# Test ModOrder +# + +# +# Test NewOrderItem +# + +# +# Test ModItemOrder +# + +# +# test GetOrder +# +# Returns a reference-to-hash describing the order. +# The keys of C<$order> are fields from the biblio, biblioitems, aqorders tables +# If the record have been suppressed, its biblionumber is only returned in deletedbiblionumber column. +# no error control + +#timestamp : 3 different +#notes +my @expectedfields = qw(biblionumber + frameworkcode + author + title + unititle + biblio_notes + serial + seriestitle + copyrightdate + biblio_timestamp + datecreated + abstract + biblioitemnumber + volume + number + itemtype + isbn + issn + ean + publicationyear + publishercode + volumedate + volumedesc + collectiontitle + collectionissn + collectionvolume + editionstatement + editionresponsibility + illus + pages + biblioitems_notes + size + place + lccn + marc + url + cn_source + cn_class + cn_item + cn_suffix + cn_sort + agerestriction + totalissues + marcxml + ordernumber + entrydate + quantity + currency + listprice + totalamount + datereceived + invoiceid + freight + unitprice + quantityreceived + cancelledby + datecancellationprinted + notes + supplierreference + purchaseordernumber + basketno + timestamp + rrp + ecost + gstrate + discount + budget_id + budgetgroup_id + budgetdate + sort1 + sort2 + sort1_authcat + sort2_authcat + uncertainprice + claims_count + claimed_date + subscriptionid + parent_ordernumber + deletedbiblionumber); +my $myorder1_beforedelete = GetOrder($ordernumber1); +my @w = keys %$myorder1_beforedelete; +#warn "@w"; +# my @C=map{!${{map{$_,1}@w}}{$_}&&$_||undef}@expectedfields; +#warn @C; +is( scalar (keys %$myorder1_beforedelete),79, "If the record is not deleted, GetOrder gets an order with the right number of fields" ); +for my $field ( @expectedfields ) { + ok( exists( $myorder1_beforedelete->{ $field } ), "If the record is not deleted, GetOrder gets an order with a $field field" ); + is(( $myorder1_beforedelete->{ $field } ) , $order1_content->{ $field },"If the record is not deleted, GetOrder gets an order with a correct content in $field" ) if (defined $order1_content->{ $field } && $field !~ /biblionumber/); +} +is(( $myorder1_beforedelete->{ biblionumber} ) , $order1_content->{ biblionumber},"If the record is not deleted, GetOrder gets an order with a correct biblionumber"); +is(( $myorder1_beforedelete->{ deletedbiblionumber} ) , undef ,"If the record is not deleted, GetOrder gets an order with a no deletedbiblionumber"); + +# GetOrders return correct informations even if the record is deleted +&C4::Biblio::DelBiblio ($biblionumber1); +my $myorder1_afterdelete = GetOrder($ordernumber1); +is( scalar (keys %$myorder1_afterdelete),79, "If the record is deleted, GetOrder gets an order with the right number of fields" ); +for my $field ( @expectedfields ) { + ok( exists( $myorder1_afterdelete->{ $field } ), "If the record is deleted, GetOrder gets an order with a $field field" ); + is (( $myorder1_afterdelete->{ $field } ), $order1_content->{ $field },"If the record is deleted, GetOrder gets an order with a correct content in $field" ) if (defined $order1_content->{ $field } && $field !~ /biblionumber/); +} +is(( $myorder1_afterdelete->{ deletedbiblionumber} ) , $order1_content->{ biblionumber},"If the record is deleted, GetOrder gets an order with a correct deletedbiblionumber"); +is(( $myorder1_afterdelete->{ biblionumber} ) , undef ,"If the record is deleted, GetOrder gets an order with a no biblionumber"); + +# +# test GetOrders +# + +# +# test GetCancelledOrders +# + +# +# test SearchOrder +# + +# +# Test GetHistory +# + +# +# Test GetLateOrders +# + +# +# Test GetOrderFromItemnumber +# + +# +# Test GetLastOrderNotReceivedFromSubscriptionid +# + +# +# Test GetLastOrderReceivedFromSubscriptionid +# + +# +# Test GetRecentAcqui +# + +# +# Test ModReceiveOrder +# + +# +# Test CancelReceipt +# + +# +# Test CancelReceipt +# + +# +# test GetLateOrders +# + +# +# test GetItemnumbersFromOrder +# + +# +# test GetPendingOrders +# + my $grouped = 0; my $orders = GetPendingOrders( $booksellerid, $grouped ); isa_ok( $orders, 'ARRAY' ); +# +# test AddClaim +# + C4::Acquisition::CloseBasket( $basketno ); my @lateorders = GetLateOrders(0); my $order = $lateorders[0]; @@ -91,7 +347,11 @@ AddClaim( $order->{ordernumber} ); my $neworder = GetOrder( $order->{ordernumber} ); is( $neworder->{claimed_date}, strftime( "%Y-%m-%d", localtime(time) ), "AddClaim : Check claimed_date" ); -my @expectedfields = qw( basketno +# +# test GetPendingOrders again +# + +@expectedfields = qw( basketno biblionumber invoiceid budgetdate @@ -127,4 +387,40 @@ for my $field ( @expectedfields ) { ok( exists( $firstorder->{ $field } ), "This order has a $field field" ); } +# +# FUNCTIONS ABOUT INVOICES +# + +# +# GetInvoice +# + +# +# GetInvoices +# + +# +# GetInvoiceDetails +# + +# +# AddInvoice +# + +# +# ModInvoice +# + +# +# CloseInvoice +# + +# +# ReopenInvoice +# + +# +# DelInvoice +# + $dbh->rollback; --- a/t/db_dependent/Biblio.t +++ a/t/db_dependent/Biblio.t @@ -5,14 +5,26 @@ use strict; use warnings; -use Test::More tests => 17; +use Test::More tests => 28; use MARC::Record; use C4::Biblio; +use C4::Items; +use C4::Branch qw( ModBranch DelBranch ); +use C4::Budgets qw( AddBudget GetBudget DelBudget AddBudgetPeriod ); +use C4::Bookseller qw( AddBookseller DelBookseller ); +use C4::Acquisition qw( NewBasket DelBasket DelOrder NewOrder GetOrder); +use C4::Serials qw( NewSubscription GetSubscription ); + +my $dbh = C4::Context->dbh; +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; BEGIN { use_ok('C4::Biblio'); } +# FIXME for the moment, Biblio.t is only working for MARC21 + my $isbn = '0590353403'; my $title = 'Foundation'; @@ -109,5 +121,123 @@ $field->update('123456789X'); $controlnumber = GetMarcControlnumber( $marc_record, 'MARC21' ); is( $controlnumber, '123456789X', 'GetMarcControlnumber handles records with 001' ); -# clean up after ourselves -DelBiblio($biblionumber); +# +# testing DelBiblio and clean up +# +# add an item, an order and a subscription +# add a branch and an item +my $b1 = { + add => 1, + branchcode => 'BRA', + branchname => 'BranchA', + branchaddress1 => 'adr1A', + branchaddress2 => 'adr2A', + branchaddress3 => 'adr3A', + branchzip => 'zipA', + branchcity => 'cityA', + branchstate => 'stateA', + branchcountry => 'countryA', + branchphone => 'phoneA', + branchfax => 'faxA', + branchemail => 'emailA', + branchurl => 'urlA', + branchip => 'ipA', + branchprinter => undef, + branchnotes => 'noteA', + opac_info => 'opacA' +}; +ModBranch($b1); +my ($item_bibnum, $item_bibitemnum, $itemnumber) = AddItem({ homebranch => 'BRA', holdingbranch => 'BRA' } , $biblionumber); +# add an order +my $booksellerid = AddBookseller( + { + name => "my vendor", + address1 => "bookseller's address", + phone => "0123456", + active => 1, + deliverytime => 5, + } +); + +my $bpid = AddBudgetPeriod({ + budget_period_startdate => '01-01-2015', + budget_period_enddate => '31-12-2015', + budget_description => "budget desc" +}); + +my $budgetid = AddBudget( + { + budget_code => "budget_code_test_1", + budget_name => "budget_name_test_1", + budget_amount => "1000.00", + budget_active => 1, + budget_period_id => $bpid + } +); +my $basketno = NewBasket($booksellerid, 1); +my $budget = GetBudget( $budgetid ); +( undef, my $ordernumber ) = NewOrder( + { + basketno => $basketno, + quantity => 2, + biblionumber => $biblionumber, + budget_id => $budget->{budget_id}, + } +); + +# add a subscription +my $subscriptionid = NewSubscription( + undef, "", undef, undef, $budgetid, $biblionumber, '01-01-2013', undef, + undef, undef, undef, undef, undef, undef, undef, undef, + '', undef, undef, undef, undef, undef, '', undef, + undef, undef, undef, undef, '', undef, '', 1, + "notes", undef, undef, undef, 1, undef, undef, 0, + "intnotes", 0, undef, undef, 0, undef, '31-12-2013', +); +# if an item is attached, DelBiblio returns "This Biblio has items attached, please delete them first before deleting this biblio " and does not delete record +my $return_DelBiblio = DelBiblio($biblionumber); +is( $return_DelBiblio , 'This Biblio has items attached, please delete them first before deleting this biblio ', 'DelBiblio returns specific error if an item is present' ); +is(GetBiblioData($biblionumber)->{biblionumber},$biblionumber,'DelBiblio does not delete record if an item is present.'); + +# Delete the item. +DelItem($dbh, $biblionumber, $itemnumber); +# if an order uses the record, and if there is no item, DelBiblio moves record to deleted* tables and updates the order +$return_DelBiblio = DelBiblio($biblionumber); +is(GetBiblioData($biblionumber),undef,"DelBiblio deletes record if no item is present but if the order is used in an order"); +isnt( $return_DelBiblio , 'This Biblio has items attached, please delete them first before deleting this biblio ', 'DelBiblio does not return specific error if no item is present' ); +my $order_after_deletion = GetOrder ($ordernumber); +is($order_after_deletion->{biblionumber},undef,"DelBiblio deletes biblionumber in order.biblionumber"); +is($order_after_deletion->{deletedbiblionumber},$biblionumber,"DelBiblio copies biblionumber in order.deletedbiblionumer"); +# FIXME to check the record is moved into deletedbiblio and deletedbiblioitems, check if title and isbn in order are the same as before record deletion +is($order_after_deletion->{title},$title,"DelBiblio moves biblio table into deletedbiblio table (test on title)"); +is($order_after_deletion->{isbn},$isbn,"DelBiblio moves biblioitems table into deletedbiblioitems table (test on isbn)"); + +# if subscriptions use the record, DelBiblio delete them +is(GetSubscription( $subscriptionid ),undef,"DelBiblio deletes subscriptions when deleting record"); + +# else (if no subscription, no item, no orders are attached) DelBiblio delete the record +# create an other record +$isbn = '1290353403'; +$title = 'Second record'; +$marc_record=MARC::Record->new; +$field = MARC::Field->new('020','','','a' => $isbn); +$marc_record->append_fields($field); +($biblionumber,$biblioitemnumber) = AddBiblio($marc_record,''); +$field = MARC::Field->new('245','','','a' => $title); +$marc_record->append_fields($field); +ModBiblio($marc_record,$biblionumber,''); +# delete this record +$return_DelBiblio = DelBiblio($biblionumber); +is(GetBiblioData($biblionumber),undef,"DelBiblio deletes record if no item is present but if the order is used in an order"); +isnt( $return_DelBiblio , 'This Biblio has items attached, please delete them first before deleting this biblio ', 'DelBiblio returns no specific error if no item is present' ); + +# check the action is recorded in Koha's log +# FIXME todo + +DelOrder($ordernumber, $biblionumber); +DelBranch($b1->{branchcode} ); +DelBasket ($basketno); +DelBudget ($budgetid); +DelBookseller($booksellerid); + +$dbh->rollback; --