1 use strict; use warnings;
2 package OpenILS::Application::Cat;
3 use OpenILS::Application::AppUtils;
4 use OpenSRF::Application;
5 use OpenILS::Application::Cat::Utils;
6 use base qw/OpenSRF::Application/;
7 use Time::HiRes qw(time);
8 use OpenSRF::EX qw(:try);
10 use OpenILS::Utils::Fieldmapper;
14 use Unicode::Normalize;
16 use OpenILS::Utils::FlatXML;
18 use OpenSRF::Utils::SettingsClient;
19 use OpenSRF::Utils::Logger qw($logger);
21 my $apputils = "OpenILS::Application::AppUtils";
23 my $utils = "OpenILS::Application::Cat::Utils";
24 my $U = "OpenILS::Application::AppUtils";
32 my $form = shift || "";
40 $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
44 __PACKAGE__->register_method(
45 method => "retrieve_marc_template",
46 api_name => "open-ils.cat.biblio.marc_template.retrieve",
48 Returns a MARC 'record tree' based on a set of pre-defined templates.
49 Templates include : book
52 sub retrieve_marc_template {
53 my( $self, $client, $type ) = @_;
55 return $marctemplates{$type} if defined($marctemplates{$type});
56 $marctemplates{$type} = _load_marc_template($type);
57 return $marctemplates{$type};
60 sub _load_marc_template {
63 if(!$conf) { $conf = OpenSRF::Utils::SettingsClient->new; }
65 my $template = $conf->config_value(
66 "apps", "open-ils.cat","app_settings", "marctemplates", $type );
67 warn "Opening template file $template\n";
69 open( F, $template ) or
70 throw OpenSRF::EX::ERROR ("Unable to open MARC template file: $template : $@");
74 my $xml = join('', @xml);
76 return XML::LibXML->new->parse_string($xml)->documentElement->toString;
81 __PACKAGE__->register_method(
82 method => "create_record_xml",
83 api_name => "open-ils.cat.biblio.record.xml.create.override",
84 signature => q/@see open-ils.cat.biblio.record.xml.create/);
86 __PACKAGE__->register_method(
87 method => "create_record_xml",
88 api_name => "open-ils.cat.biblio.record.xml.create",
90 Inserts a new biblio with the given XML
94 sub create_record_xml {
95 my( $self, $client, $login, $xml, $source ) = @_;
98 my $override = 1 if $self->api_name =~ /override/;
100 my( $user_obj, $evt ) = $U->checksesperm($login, 'CREATE_MARC');
103 $logger->activity("user ".$user_obj->id." creating new MARC record");
105 my $meth = $self->method_lookup("open-ils.cat.biblio.record.xml.import");
107 $meth = $self->method_lookup(
108 "open-ils.cat.biblio.record.xml.import.override") if $override;
110 my ($s) = $meth->run($login, $xml, 2);
117 __PACKAGE__->register_method(
118 method => "biblio_record_xml_import",
119 api_name => "open-ils.cat.biblio.record.xml.import.override",
120 signature => q/@see open-ils.cat.biblio.record.xml.import/);
122 __PACKAGE__->register_method(
123 method => "biblio_record_xml_import",
124 api_name => "open-ils.cat.biblio.record.xml.import",
125 notes => <<" NOTES");
126 Takes a marcxml record and imports the record into the database. In this
127 case, the marcxml record is assumed to be a complete record (i.e. valid
128 MARC). The title control number is taken from (whichever comes first)
129 tags 001, 039[ab], 020a, 022a, 010, 035a and whichever does not already exist
131 user_session must have IMPORT_MARC permissions
135 sub biblio_record_xml_import {
136 my( $self, $client, $authtoken, $xml, $source) = @_;
138 my ($tcn, $tcn_source);
140 my $override = 1 if $self->api_name =~ /override/;
142 my( $requestor, $evt ) = $U->checksesperm($authtoken, 'IMPORT_MARC');
145 my $session = $apputils->start_db_session();
148 my $marcxml = XML::LibXML->new->parse_string( $xml );
149 $marcxml->documentElement->setNamespace(
150 "http://www.loc.gov/MARC21/slim", "marc", 1 );
152 my $xpath = '//marc:controlfield[@tag="001"]';
153 $tcn = $marcxml->documentElement->findvalue($xpath);
154 $logger->info("biblio import located 001 (tcn) value of $tcn");
156 $xpath = '//marc:controlfield[@tag="003"]';
157 $tcn_source = $marcxml->documentElement->findvalue($xpath) || "System Local";
159 if(my $rec = _tcn_exists($session, $tcn, $tcn_source)) {
162 $tcn = find_free_tcn( $marcxml, $session );
164 # if we're overriding, try to find a different TCN to use
167 $logger->activity("tcn value $tcn already exists, attempting to override");
170 return OpenILS::Event->new(
171 'OPEN_TCN_NOT_FOUND', payload => $marcxml->toString());
176 $logger->warn("tcn value $origtcn already exists in import/create");
178 # otherwise, return event
179 return OpenILS::Event->new(
180 'TCN_EXISTS', payload => {
189 $logger->activity("user ".$requestor->id.
190 " creating new biblio entry with tcn=$tcn and tcn_source $tcn_source");
194 my $record = Fieldmapper::biblio::record_entry->new;
196 $record->source($source) if ($source);
197 $record->tcn_source($tcn_source);
198 $record->tcn_value($tcn);
199 $record->creator($requestor->id);
200 $record->editor($requestor->id);
201 $record->marc( entityize( $marcxml->documentElement->toString ) );
203 my $id = $session->request(
204 "open-ils.storage.direct.biblio.record_entry.create", $record )->gather(1);
206 return $U->DB_UPDATE_FAILED($record) unless $id;
209 $logger->info("marc create/import created new record $id");
211 $apputils->commit_db_session($session);
213 $logger->debug("Sending record off to be wormized");
215 my $stat = $U->storagereq( 'open-ils.worm.wormize.biblio', $id );
216 throw OpenSRF::EX::ERROR
217 ("Unable to wormize imported record") unless $stat;
229 my $xpath = '//marc:datafield[@tag="039"]/subfield[@code="a"]';
230 my ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
231 $xpath = '//marc:datafield[@tag="039"]/subfield[@code="b"]';
232 my $tcn_source = $marcxml->documentElement->findvalue($xpath) || "System Local";
234 if(_tcn_exists($session, $tcn, $tcn_source)) {
242 $xpath = '//marc:datafield[@tag="020"]/subfield[@code="a"]';
243 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
244 $tcn_source = "ISBN";
245 if(_tcn_exists($session, $tcn, $tcn_source)) {$tcn = undef;}
249 $xpath = '//marc:datafield[@tag="022"]/subfield[@code="a"]';
250 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
251 $tcn_source = "ISSN";
252 if(_tcn_exists($session, $tcn, $tcn_source)) {$tcn = undef;}
256 $xpath = '//marc:datafield[@tag="010"]';
257 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
258 $tcn_source = "LCCN";
259 if(_tcn_exists($session, $tcn, $tcn_source)) {$tcn = undef;}
263 $xpath = '//marc:datafield[@tag="035"]/subfield[@code="a"]';
264 ($tcn) = $marcxml->documentElement->findvalue($xpath) =~ /(\w+)\s*$/o;
265 $tcn_source = "System Legacy";
266 if(_tcn_exists($session, $tcn, $tcn_source)) {$tcn = undef;}
269 $marcxml->documentElement->removeChild(
270 $marcxml->documentElement->findnodes( '//datafield[@tag="035"]' )
276 my $df = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'datafield');
277 $df->setAttribute( tag => '039' );
278 $df->setAttribute( ind1 => ' ' );
279 $df->setAttribute( ind2 => ' ' );
280 $marcxml->documentElement->appendChild( $df );
282 my $sfa = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'subfield');
283 $sfa->setAttribute( code => 'a' );
284 $sfa->appendChild( $marcxml->createTextNode( $tcn ) );
285 $df->appendChild( $sfa );
287 my $sfb = $marcxml->createElementNS( 'http://www.loc.gov/MARC21/slim', 'subfield');
288 $sfb->setAttribute( code => 'b' );
289 $sfb->appendChild( $marcxml->createTextNode( $tcn_source ) );
290 $df->appendChild( $sfb );
303 if(!$tcn) {return 0;}
305 $logger->debug("tcn_exists search for tcn $tcn and source $source");
307 my $req = $session->request(
308 "open-ils.storage.id_list.biblio.record_entry.search_where.atomic",
309 { tcn_value => $tcn, tcn_source => $source, deleted => 'f' } );
311 my $recs = $req->gather(1);
313 if($recs and $recs->[0]) {
314 $logger->debug("_tcn_exists is true for tcn : $tcn ($source)");
318 $logger->debug("_tcn_exists is false for tcn : $tcn ($source)");
324 __PACKAGE__->register_method(
325 method => "biblio_record_tree_retrieve",
326 api_name => "open-ils.cat.biblio.record.tree.retrieve",
329 sub biblio_record_tree_retrieve {
331 my( $self, $client, $recordid ) = @_;
333 my $name = "open-ils.storage.direct.biblio.record_entry.retrieve";
334 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
335 my $request = $session->request( $name, $recordid );
336 my $marcxml = $request->gather(1);
339 throw OpenSRF::EX::ERROR
340 ("No record in database with id $recordid");
343 $session->disconnect();
346 warn "turning into nodeset\n";
347 my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $marcxml->marc );
348 warn "turning nodeset into tree\n";
349 my $tree = $utils->nodeset2tree( $nodes->nodeset );
351 $tree->owner_doc( $marcxml->id() );
353 warn "returning tree\n";
358 __PACKAGE__->register_method(
359 method => "biblio_record_xml_update",
360 api_name => "open-ils.cat.biblio.record.xml.update",
361 argc => 3, #(session_id, biblio_tree )
362 notes => <<' NOTES');
363 Updates the XML of a biblio record entry
364 @param authtoken The session token for the staff updating the record
365 @param docID The record entry ID to update
366 @param xml The new MARCXML record
369 sub biblio_record_xml_update {
371 my( $self, $client, $user_session, $id, $xml ) = @_;
373 my $user_obj = $apputils->check_user_session($user_session);
375 if($apputils->check_user_perms(
376 $user_obj->id, $user_obj->home_ou, "UPDATE_MARC")) {
377 return OpenILS::Perm->new("UPDATE_MARC");
380 $logger->activity("user ".$user_obj->id." updating biblio record $id");
383 my $session = OpenILS::Application::AppUtils->start_db_session();
385 warn "Retrieving biblio record from storage for update\n";
387 my $req1 = $session->request(
388 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", $id );
389 my $biblio = $req1->gather(1);
391 warn "retrieved doc $id\n";
393 my $doc = XML::LibXML->new->parse_string($xml);
394 throw OpenSRF::EX::ERROR ("Invalid XML in record update: $xml") unless $doc;
396 $biblio->marc( entityize( $doc->documentElement->toString ) );
397 $biblio->editor( $user_obj->id );
398 $biblio->edit_date( 'now' );
400 warn "Sending updated doc $id to db with xml ".$biblio->marc. "\n";
402 my $req = $session->request(
403 "open-ils.storage.direct.biblio.record_entry.update", $biblio );
406 my $status = $req->recv();
407 if( !$status || $status->isa("Error") || ! $status->content) {
408 OpenILS::Application::AppUtils->rollback_db_session($session);
409 if($status->isa("Error")) { throw $status ($status); }
410 throw OpenSRF::EX::ERROR ("Error updating biblio record");
414 # Send the doc to the wormer for wormizing
415 warn "Starting worm session\n";
420 my $wreq = $session->request( "open-ils.worm.wormize.biblio", $id );
424 $w = $wreq->gather(1);
428 warn "wormizing failed, rolling back\n";
429 OpenILS::Application::AppUtils->rollback_db_session($session);
431 if($e) { throw $e ($e); }
432 throw OpenSRF::EX::ERROR ("Wormizing Failed for $id" );
435 warn "Committing db session...\n";
436 OpenILS::Application::AppUtils->commit_db_session( $session );
438 # $client->respond_complete($tree);
440 warn "Done wormizing\n";
443 #warn "Returning tree:\n";
452 __PACKAGE__->register_method(
453 method => "biblio_record_record_metadata",
454 api_name => "open-ils.cat.biblio.record.metadata.retrieve",
455 argc => 1, #(session_id, biblio_tree )
456 notes => "Walks the tree and commits any changed nodes " .
457 "adds any new nodes, and deletes any deleted nodes",
460 sub biblio_record_record_metadata {
461 my( $self, $client, @ids ) = @_;
463 if(!@ids){return undef;}
465 my $session = OpenSRF::AppSession->create("open-ils.storage");
466 my $request = $session->request(
467 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
471 while( my $response = $request->recv() ) {
474 throw OpenSRF::EX::ERROR ("No Response from Storage");
476 if($response->isa("Error")) {
477 throw $response ($response->stringify);
480 my $record_entry = $response->content;
482 my $creator = $record_entry->creator;
483 my $editor = $record_entry->editor;
485 ($creator, $editor) = _get_userid_by_id($creator, $editor);
487 $record_entry->creator($creator);
488 $record_entry->editor($editor);
490 push @$results, $record_entry;
495 $session->disconnect();
502 __PACKAGE__->register_method(
503 method => "biblio_record_marc_cn",
504 api_name => "open-ils.cat.biblio.record.marc_cn.retrieve",
505 argc => 1, #(bib id )
508 sub biblio_record_marc_cn {
509 my( $self, $client, $id ) = @_;
511 my $session = OpenSRF::AppSession->create("open-ils.storage");
513 ->request("open-ils.storage.direct.biblio.record_entry.retrieve", $id )
517 my $doc = XML::LibXML->new->parse_string($marc);
518 $doc->documentElement->setNamespace( "http://www.loc.gov/MARC21/slim", "marc", 1 );
521 for my $tag ( qw/050 055 060 070 080 082 086 088 090 092 096 098 099/ ) {
522 my @node = $doc->findnodes("//marc:datafield[\@tag='$tag']");
524 my $cn = $x->findvalue("marc:subfield[\@code='a' or \@code='b']");
525 push @res, {$tag => $cn} if ($cn);
533 sub _get_userid_by_id {
538 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
539 my $request = $session->request(
540 "open-ils.storage.direct.actor.user.batch.retrieve.atomic", @ids );
542 $request->wait_complete;
543 my $response = $request->recv();
544 if(!$request->complete) { return undef; }
546 if($response->isa("Error")){
547 throw $response ($response);
550 for my $u (@{$response->content}) {
552 push @users, $u->usrname;
556 $session->disconnect;
562 sub _get_id_by_userid {
567 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
568 my $request = $session->request(
569 "open-ils.storage.direct.actor.user.search.usrname.atomic", @users );
571 $request->wait_complete;
572 my $response = $request->recv();
573 if(!$request->complete) {
574 throw OpenSRF::EX::ERROR ("no response from storage on user retrieve");
577 if(UNIVERSAL::isa( $response, "Error")){
578 throw $response ($response);
581 for my $u (@{$response->content}) {
587 $session->disconnect;
594 # commits metadata objects to the db
595 sub _update_record_metadata {
597 my ($session, @docs ) = @_;
599 for my $doc (@docs) {
601 my $user_obj = $doc->{user};
602 my $docid = $doc->{docid};
604 warn "Updating metata for doc $docid\n";
606 my $request = $session->request(
607 "open-ils.storage.direct.biblio.record_entry.retrieve", $docid );
608 my $record = $request->gather(1);
610 warn "retrieved record\n";
611 my ($id) = _get_id_by_userid($user_obj->usrname);
613 warn "got $id from _get_id_by_userid\n";
614 $record->editor($id);
616 warn "Grabbed the record, updating and moving on\n";
618 $request = $session->request(
619 "open-ils.storage.direct.biblio.record_entry.update", $record );
623 warn "committing metarecord update\n";
630 __PACKAGE__->register_method(
631 method => "orgs_for_title",
632 api_name => "open-ils.cat.actor.org_unit.retrieve_by_title"
636 my( $self, $client, $record_id ) = @_;
638 my $vols = $apputils->simple_scalar_request(
640 "open-ils.storage.direct.asset.call_number.search_where.atomic",
641 { record => $record_id, deleted => 'f' });
642 #"open-ils.storage.direct.asset.call_number.search.record.atomic",
644 my $orgs = { map {$_->owning_lib => 1 } @$vols };
645 return [ keys %$orgs ];
649 __PACKAGE__->register_method(
650 method => "retrieve_copies",
651 api_name => "open-ils.cat.asset.copy_tree.retrieve");
653 __PACKAGE__->register_method(
654 method => "retrieve_copies",
655 api_name => "open-ils.cat.asset.copy_tree.global.retrieve");
657 # user_session may be null/undef
658 sub retrieve_copies {
660 my( $self, $client, $user_session, $docid, @org_ids ) = @_;
662 if(ref($org_ids[0])) { @org_ids = @{$org_ids[0]}; }
666 warn " $$ retrieving copy tree for orgs @org_ids and doc $docid at " . time() . "\n";
668 # grabbing copy trees should be available for everyone..
669 if(!@org_ids and $user_session) {
671 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
672 @org_ids = ($user_obj->home_ou);
675 if( $self->api_name =~ /global/ ) {
676 warn "performing global copy_tree search for $docid\n";
677 return _build_volume_list( { record => $docid } );
682 for my $orgid (@org_ids) {
683 my $vols = _build_volume_list(
684 { record => $docid, owning_lib => $orgid } );
685 warn "Volumes built for org $orgid\n";
686 push( @all_vols, @$vols );
689 warn " $$ Finished copy_tree at " . time() . "\n";
697 sub _build_volume_list {
698 my $search_hash = shift;
700 $search_hash->{deleted} = 'f';
702 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
705 my $request = $session->request(
706 "open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
707 #"open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
709 my $vols = $request->gather(1);
712 for my $volume (@$vols) {
714 warn "Grabbing copies for volume: " . $volume->id . "\n";
715 my $creq = $session->request(
716 "open-ils.storage.direct.asset.copy.search_where.atomic",
717 { call_number => $volume->id , deleted => 'f' });
718 #"open-ils.storage.direct.asset.copy.search.call_number.atomic", $volume->id );
720 my $copies = $creq->gather(1);
722 $copies = [ sort { $a->barcode cmp $b->barcode } @$copies ];
724 $volume->copies($copies);
726 push( @volumes, $volume );
730 $session->disconnect();
736 # -----------------------------------------------------------------
737 # Fleshed volume tree batch add/update. This does everything a
738 # volume tree could want, add, update, delete
739 # -----------------------------------------------------------------
740 __PACKAGE__->register_method(
741 method => "volume_tree_fleshed_update",
742 api_name => "open-ils.cat.asset.volume_tree.fleshed.batch.update",
744 sub volume_tree_fleshed_update {
746 my( $self, $client, $user_session, $volumes ) = @_;
747 return undef unless $volumes;
749 my $user_obj = $apputils->check_user_session($user_session);
752 my $session = $apputils->start_db_session();
753 warn "Looping on volumes in fleshed volume tree update\n";
755 # cycle through the volumes provided and update/create/delete where necessary
756 for my $volume (@$volumes) {
758 warn "updating volume " . $volume->id . "\n";
760 my $update_copy_list = $volume->copies;
763 if( $volume->isdeleted) {
764 my $status = _delete_volume($session, $volume, $user_obj);
766 #throw OpenSRF::EX::ERROR
767 #("Volume delete failed for volume " . $volume->id);
769 if(UNIVERSAL::isa($status, "Fieldmapper::perm_ex")) { return $status; }
771 } elsif( $volume->isnew ) {
774 $volume->editor($user_obj->id);
775 $volume->creator($user_obj->id);
776 $volume = _add_volume($session, $volume, $user_obj);
779 if($volume and UNIVERSAL::isa($volume, "Fieldmapper::perm_ex")) { return $volume; }
781 } elsif( $volume->ischanged ) {
783 $volume->editor($user_obj->id);
784 my $stat = _update_volume($session, $volume, $user_obj);
785 if($stat and UNIVERSAL::isa($stat, "Fieldmapper::perm_ex")) { return $stat; }
789 if( ! $volume->isdeleted ) {
790 for my $copy (@{$update_copy_list}) {
792 $copy->editor($user_obj->id);
793 warn "updating copy for volume " . $volume->id . "\n";
798 $copy->call_number($volume->id);
799 $copy->creator($user_obj->id);
800 $copy = _fleshed_copy_update($session,$copy,$user_obj);
802 } elsif( $copy->ischanged ) {
803 $copy->call_number($volume->id);
804 $copy = _fleshed_copy_update($session, $copy, $user_obj);
806 } elsif( $copy->isdeleted ) {
807 warn "Deleting copy " . $copy->id . " for volume " . $volume->id . "\n";
808 my $status = _fleshed_copy_update($session, $copy, $user_obj);
809 warn "Copy delete returned a status of $status\n";
815 $apputils->commit_db_session($session);
816 return scalar(@$volumes);
821 my( $session, $volume, $user_obj ) = @_;
823 if($apputils->check_user_perms(
824 $user_obj->id, $user_obj->home_ou, "DELETE_VOLUME")) {
825 return OpenILS::Perm->new("DELETE_VOLUME"); }
827 #$volume = _find_volume($session, $volume);
828 warn "Deleting volume " . $volume->id . "\n";
830 my $copies = $session->request(
831 "open-ils.storage.direct.asset.copy.search_where.atomic",
832 { call_number => $volume->id, deleted => 'f' } )->gather(1);
833 #"open-ils.storage.direct.asset.copy.search.call_number.atomic",
836 throw OpenSRF::EX::ERROR
837 ("Cannot remove volume with copies attached");
840 my $req = $session->request(
841 "open-ils.storage.direct.asset.call_number.delete",
843 return $req->gather(1);
848 my($session, $volume, $user_obj) = @_;
849 if($apputils->check_user_perms(
850 $user_obj->id, $user_obj->home_ou, "UPDATE_VOLUME")) {
851 return OpenILS::Perm->new("UPDATE_VOLUME"); }
853 my $req = $session->request(
854 "open-ils.storage.direct.asset.call_number.update",
856 my $status = $req->gather(1);
861 my($session, $volume, $user_obj) = @_;
863 if($apputils->check_user_perms(
864 $user_obj->id, $user_obj->home_ou, "CREATE_VOLUME")) {
865 warn "User does not have priveleges to create new volumes\n";
866 return OpenILS::Perm->new("CREATE_VOLUME");
869 my $request = $session->request(
870 "open-ils.storage.direct.asset.call_number.create", $volume );
872 my $id = $request->gather(1);
875 OpenILS::Application::AppUtils->rollback_db_session($session);
876 throw OpenSRF::EX::ERROR (" * -> Error creating new volume");
880 warn "received new volume id: $id\n";
888 __PACKAGE__->register_method(
889 method => "fleshed_copy_update",
890 api_name => "open-ils.cat.asset.copy.fleshed.batch.update",
893 sub fleshed_copy_update {
894 my($self, $client, $user_session, $copies) = @_;
896 my $user_obj = $apputils->check_user_session($user_session);
897 my $session = $apputils->start_db_session();
899 for my $copy (@$copies) {
900 _fleshed_copy_update($session, $copy, $user_obj);
903 $apputils->commit_db_session($session);
910 my($session, $copy, $user_obj) = @_;
912 if($apputils->check_user_perms(
913 $user_obj->id, $user_obj->home_ou, "DELETE_COPY")) {
914 return OpenILS::Perm->new("DELETE_COPY"); }
916 warn "Deleting copy " . $copy->id . "\n";
917 my $request = $session->request(
918 "open-ils.storage.direct.asset.copy.delete",
920 return $request->gather(1);
924 my($session, $copy, $user_obj) = @_;
926 if($apputils->check_user_perms(
927 $user_obj->id, $user_obj->home_ou, "CREATE_COPY")) {
928 return OpenILS::Perm->new("CREATE_COPY"); }
930 my $request = $session->request(
931 "open-ils.storage.direct.asset.copy.create",
933 my $id = $request->gather(1);
936 throw OpenSRF::EX::ERROR
937 ("Unable to create new copy " . Dumper($copy));
940 warn "Created copy " . $copy->id . "\n";
947 my($session, $copy, $user_obj) = @_;
949 my $evt = $apputils->check_perms($user_obj->id, $copy->circ_lib, 'UPDATE_COPY');
950 return $evt if $evt; #XXX NOT YET HANDLED BY CALLER
952 my $status = $apputils->simplereq(
954 "open-ils.storage.direct.asset.copy.update", $copy );
955 $logger->debug("Successfully updated copy " . $copy->id );
960 # -----------------------------------------------------------------
961 # Creates/Updates/Deletes a fleshed asset.copy.
962 # adds/deletes copy stat_cat maps where necessary
963 # -----------------------------------------------------------------
964 sub _fleshed_copy_update {
965 my($session, $copy, $editor) = @_;
967 my $stat_cat_entries = $copy->stat_cat_entries;
968 $copy->editor($editor->id);
970 # in case we're fleshed
971 if(ref($copy->status)) {$copy->status( $copy->status->id ); }
972 if(ref($copy->location)) {$copy->location( $copy->location->id ); }
973 if(ref($copy->circ_lib)) {$copy->circ_lib( $copy->circ_lib->id ); }
975 warn "Updating copy " . Dumper($copy) . "\n";
977 if( $copy->isdeleted ) {
978 return _delete_copy($session, $copy, $editor);
979 } elsif( $copy->isnew ) {
980 $copy = _create_copy($session, $copy, $editor);
981 } elsif( $copy->ischanged ) {
982 _update_copy($session, $copy, $editor);
986 return 1 unless ( $stat_cat_entries and @$stat_cat_entries );
988 my $stat_maps = $session->request(
989 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.search.owning_copy.atomic",
990 $copy->id )->gather(1);
992 if(!$copy->isnew) { _delete_stale_maps($session, $stat_maps, $copy); }
994 # go through the stat cat update/create process
995 for my $stat_entry (@{$stat_cat_entries}){
996 _copy_update_stat_cats( $session, $copy, $stat_maps, $stat_entry, $editor );
1003 # -----------------------------------------------------------------
1004 # Deletes stat maps attached to this copy in the database that
1005 # are no longer attached to the current copy
1006 # -----------------------------------------------------------------
1007 sub _delete_stale_maps {
1008 my( $session, $stat_maps, $copy) = @_;
1010 warn "Deleting stale stat maps for copy " . $copy->id . "\n";
1011 for my $map (@$stat_maps) {
1012 # if there is no stat cat entry on the copy who's id matches the
1013 # current map's id, remove the map from the database
1014 if(! grep { $_->id == $map->stat_cat_entry } @{$copy->stat_cat_entries} ) {
1015 my $req = $session->request(
1016 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.delete", $map );
1025 # -----------------------------------------------------------------
1026 # Searches the stat maps to see if '$entry' already exists on
1027 # the given copy. If it does not, a new stat map is created
1028 # for the given entry and copy
1029 # -----------------------------------------------------------------
1030 sub _copy_update_stat_cats {
1031 my ( $session, $copy, $stat_maps, $entry, $editor ) = @_;
1033 warn "Updating stat maps for copy " . $copy->id . "\n";
1035 # see if this map already exists
1036 for my $map (@$stat_maps) {
1037 if( $map->stat_cat_entry == $entry->id ) {return;}
1040 warn "Creating new stat map for stat " .
1041 $entry->stat_cat . " and copy " . $copy->id . "\n";
1044 my $new_map = Fieldmapper::asset::stat_cat_entry_copy_map->new();
1046 $new_map->stat_cat( $entry->stat_cat );
1047 $new_map->stat_cat_entry( $entry->id );
1048 $new_map->owning_copy( $copy->id );
1050 warn "New map is " . Dumper($new_map) . "\n";
1052 my $request = $session->request(
1053 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.create",
1055 my $status = $request->gather(1);
1056 warn "created new map with id $status\n";