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;
13 use OpenILS::Utils::FlatXML;
15 use OpenSRF::Utils::SettingsClient;
17 my $apputils = "OpenILS::Application::AppUtils";
19 my $utils = "OpenILS::Application::Cat::Utils";
26 __PACKAGE__->register_method(
27 method => "retrieve_marc_template",
28 api_name => "open-ils.cat.biblio.marc_template.retrieve",
30 Returns a MARC 'record tree' based on a set of pre-defined templates.
31 Templates include : book
34 sub retrieve_marc_template {
35 my( $self, $client, $type ) = @_;
37 return $marctemplates{$type} if defined($marctemplates{$type});
39 my $xml = _load_marc_template($type);
41 my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $xml );
42 $marctemplates{$type} = $utils->nodeset2tree( $nodes->nodeset );
43 return $marctemplates{$type};
46 sub _load_marc_template {
49 if(!$conf) { $conf = OpenSRF::Utils::SettingsClient->new; }
51 my $template = $conf->config_value(
52 "apps", "open-ils.cat","app_settings", "marctemplates", $type );
53 warn "Opening template file $template\n";
58 return join('', @xml);
64 __PACKAGE__->register_method(
65 method => "create_record_tree",
66 api_name => "open-ils.cat.biblio.record_tree.create",
68 Inserts a new MARC 'record tree' into the system
71 sub create_record_tree {
72 my( $self, $client, $login, $tree ) = @_;
74 my $user_obj = $apputils->check_user_session($login);
76 if($apputils->check_user_perms(
77 $user_obj->id, $user_obj->home_ou, "CREATE_MARC")) {
78 return OpenILS::Perm->new("CREATE_MARC");
81 warn "Creating a new record tree entry...";
82 my $meth = $self->method_lookup("open-ils.cat.biblio.record.tree.import");
83 my ($s) = $meth->run($login, $tree);
90 __PACKAGE__->register_method(
91 method => "biblio_record_tree_import",
92 api_name => "open-ils.cat.biblio.record.tree.import",
94 Takes a record tree and imports the record into the database. In this
95 case, the record tree is assumed to be a complete record (i.e. valid
96 MARC. The title control number is taken from (whichever comes first)
97 tags 001, 020, 022, 010, 035 and whichever does not already exist
99 user_session must have IMPORT_MARC permissions
103 sub biblio_record_tree_import {
104 my( $self, $client, $user_session, $tree) = @_;
105 my $user_obj = $apputils->check_user_session($user_session);
107 if($apputils->check_user_perms(
108 $user_obj->id, $user_obj->home_ou, "IMPORT_MARC")) {
109 return OpenILS::Perm->new("IMPORT_MARC");
112 warn "importing new record " . Dumper($tree) . "\n";
114 my $nodeset = $utils->tree2nodeset($tree);
115 warn "turned into nodeset " . Dumper($nodeset) . "\n";
117 # copy the doc so that we can mangle the namespace.
118 my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml($nodeset);
119 my $copy_marcxml = XML::LibXML->new->parse_string($marcxml->toString);
121 $marcxml->documentElement->setNamespace( "http://www.loc.gov/MARC21/slim", "marc", 1 );
125 warn "Starting db session in import\n";
126 my $session = $apputils->start_db_session();
127 my $source = 2; # system local source
129 my $xpath = '//controlfield[@tag="001"]';
130 $tcn = $marcxml->documentElement->findvalue($xpath);
131 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
132 my $tcn_source = "External";
136 $xpath = '//datafield[@tag="020"]';
137 $tcn = $marcxml->documentElement->findvalue($xpath);
138 $tcn_source = "ISBN";
139 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
143 $xpath = '//datafield[@tag="022"]';
144 $tcn = $marcxml->documentElement->findvalue($xpath);
145 $tcn_source = "ISSN";
146 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
150 $xpath = '//datafield[@tag="010"]';
151 $tcn = $marcxml->documentElement->findvalue($xpath);
152 $tcn_source = "LCCN";
153 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
157 $xpath = '//datafield[@tag="035"]';
158 $tcn = $marcxml->documentElement->findvalue($xpath);
159 $tcn_source = "System";
160 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
166 warn "Record import with tcn: $tcn and source $tcn_source\n";
168 my $record = Fieldmapper::biblio::record_entry->new;
170 $record->source($source);
171 $record->tcn_source($tcn_source);
172 $record->tcn_value($tcn);
173 $record->creator($user_obj->id);
174 $record->editor($user_obj->id);
175 $record->marc($copy_marcxml->toString);
178 my $req = $session->request(
179 "open-ils.storage.direct.biblio.record_entry.create", $record );
181 my $id = $req->gather(1);
183 if(!$id) { throw OpenSRF::EX::ERROR ("Unable to create new record_entry from import"); }
184 warn "received id: $id from record_entry create\n";
186 $apputils->commit_db_session($session);
188 $session = OpenSRF::AppSession->create("open-ils.storage");
190 my $wreq = $session->request("open-ils.worm.wormize.biblio", $id)->gather(1);
191 warn "Done worming record $id\n";
193 if(!$wreq) { throw OpenSRF::EX::ERROR ("Unable to wormize imported record"); }
195 return $self->biblio_record_tree_retrieve($client, $id);
203 if(!$tcn) {return 0;}
205 my $req = $session->request(
206 "open-ils.storage.direct.biblio.record_entry.search.tcn_value.atomic",
208 my $recs = $req->gather(1);
210 if($recs and $recs->[0]) {
218 __PACKAGE__->register_method(
219 method => "biblio_record_tree_retrieve",
220 api_name => "open-ils.cat.biblio.record.tree.retrieve",
223 sub biblio_record_tree_retrieve {
225 my( $self, $client, $recordid ) = @_;
227 my $name = "open-ils.storage.direct.biblio.record_entry.retrieve";
228 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
229 my $request = $session->request( $name, $recordid );
230 my $marcxml = $request->gather(1);
233 throw OpenSRF::EX::ERROR
234 ("No record in database with id $recordid");
237 $session->disconnect();
240 warn "turning into nodeset\n";
241 my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $marcxml->marc );
242 warn "turning nodeset into tree\n";
243 my $tree = $utils->nodeset2tree( $nodes->nodeset );
245 $tree->owner_doc( $marcxml->id() );
247 warn "returning tree\n";
252 __PACKAGE__->register_method(
253 method => "biblio_record_tree_commit",
254 api_name => "open-ils.cat.biblio.record.tree.commit",
255 argc => 3, #(session_id, biblio_tree )
256 notes => <<" NOTES");
257 Walks the tree and commits any changed nodes
258 adds any new nodes, and deletes any deleted nodes
259 The record to commit must already exist or this
263 sub biblio_record_tree_commit {
265 my( $self, $client, $user_session, $tree ) = @_;
267 throw OpenSRF::EX::InvalidArg
268 ("Not enough args to to open-ils.cat.biblio.record.tree.commit")
269 unless ( $user_session and $tree );
271 my $user_obj = $apputils->check_user_session($user_session);
273 if($apputils->check_user_perms(
274 $user_obj->id, $user_obj->home_ou, "UPDATE_MARC")) {
275 return OpenILS::Perm->new("UPDATE_MARC");
280 my $docid = $tree->owner_doc();
281 my $session = OpenILS::Application::AppUtils->start_db_session();
283 warn "Retrieving biblio record from storage for update\n";
285 my $req1 = $session->request(
286 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", $docid );
287 my $biblio = $req1->gather(1);
289 warn "retrieved doc $docid\n";
292 # turn the tree into a nodeset
293 my $nodeset = $utils->tree2nodeset($tree);
294 $nodeset = $utils->clean_nodeset($nodeset);
296 if(!defined($docid)) { # be sure
297 for my $node (@$nodeset) {
298 $docid = $node->owner_doc();
299 last if defined($docid);
303 # turn the nodeset into a doc
304 my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml( $nodeset );
306 $biblio->marc( $marcxml->toString() );
308 warn "Starting db session\n";
310 my $x = _update_record_metadata( $session, { user => $user_obj, docid => $docid } );
311 OpenILS::Application::AppUtils->rollback_db_session($session) unless $x;
313 warn "Sending updated doc $docid to db\n";
314 my $req = $session->request( "open-ils.storage.direct.biblio.record_entry.update", $biblio );
317 my $status = $req->recv();
318 if( !$status || $status->isa("Error") || ! $status->content) {
319 OpenILS::Application::AppUtils->rollback_db_session($session);
320 if($status->isa("Error")) { throw $status ($status); }
321 throw OpenSRF::EX::ERROR ("Error updating biblio record");
325 # Send the doc to the wormer for wormizing
326 warn "Starting worm session\n";
331 my $wreq = $session->request( "open-ils.worm.wormize.biblio", $docid );
338 warn "wormizing failed, rolling back\n";
339 OpenILS::Application::AppUtils->rollback_db_session($session);
341 if($e) { throw $e ($e); }
342 throw OpenSRF::EX::ERROR ("Wormizing Failed for $docid" );
345 warn "Committing db session...\n";
346 OpenILS::Application::AppUtils->commit_db_session( $session );
348 $nodeset = OpenILS::Utils::FlatXML->new()->xmldoc_to_nodeset($marcxml);
349 $tree = $utils->nodeset2tree($nodeset->nodeset);
350 $tree->owner_doc($docid);
352 # $client->respond_complete($tree);
354 warn "Done wormizing\n";
357 #warn "Returning tree:\n";
366 __PACKAGE__->register_method(
367 method => "biblio_record_record_metadata",
368 api_name => "open-ils.cat.biblio.record.metadata.retrieve",
369 argc => 1, #(session_id, biblio_tree )
370 notes => "Walks the tree and commits any changed nodes " .
371 "adds any new nodes, and deletes any deleted nodes",
374 sub biblio_record_record_metadata {
375 my( $self, $client, @ids ) = @_;
377 if(!@ids){return undef;}
379 my $session = OpenSRF::AppSession->create("open-ils.storage");
380 my $request = $session->request(
381 "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
385 while( my $response = $request->recv() ) {
388 throw OpenSRF::EX::ERROR ("No Response from Storage");
390 if($response->isa("Error")) {
391 throw $response ($response->stringify);
394 my $record_entry = $response->content;
396 my $creator = $record_entry->creator;
397 my $editor = $record_entry->editor;
399 ($creator, $editor) = _get_userid_by_id($creator, $editor);
401 $record_entry->creator($creator);
402 $record_entry->editor($editor);
404 push @$results, $record_entry;
409 $session->disconnect();
417 sub _get_userid_by_id {
422 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
423 my $request = $session->request(
424 "open-ils.storage.direct.actor.user.batch.retrieve.atomic", @ids );
426 $request->wait_complete;
427 my $response = $request->recv();
428 if(!$request->complete) { return undef; }
430 if($response->isa("Error")){
431 throw $response ($response);
434 for my $u (@{$response->content}) {
436 push @users, $u->usrname;
440 $session->disconnect;
446 sub _get_id_by_userid {
451 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
452 my $request = $session->request(
453 "open-ils.storage.direct.actor.user.search.usrname.atomic", @users );
455 $request->wait_complete;
456 my $response = $request->recv();
457 if(!$request->complete) {
458 throw OpenSRF::EX::ERROR ("no response from storage on user retrieve");
461 if(UNIVERSAL::isa( $response, "Error")){
462 throw $response ($response);
465 for my $u (@{$response->content}) {
471 $session->disconnect;
478 # commits metadata objects to the db
479 sub _update_record_metadata {
481 my ($session, @docs ) = @_;
483 for my $doc (@docs) {
485 my $user_obj = $doc->{user};
486 my $docid = $doc->{docid};
488 warn "Updating metata for doc $docid\n";
490 my $request = $session->request(
491 "open-ils.storage.direct.biblio.record_entry.retrieve", $docid );
492 my $record = $request->gather(1);
494 warn "retrieved record\n";
495 my ($id) = _get_id_by_userid($user_obj->usrname);
497 warn "got $id from _get_id_by_userid\n";
498 $record->editor($id);
500 warn "Grabbed the record, updating and moving on\n";
502 $request = $session->request(
503 "open-ils.storage.direct.biblio.record_entry.update", $record );
507 warn "committing metarecord update\n";
514 __PACKAGE__->register_method(
515 method => "orgs_for_title",
516 api_name => "open-ils.cat.actor.org_unit.retrieve_by_title"
520 my( $self, $client, $record_id ) = @_;
522 my $vols = $apputils->simple_scalar_request(
524 "open-ils.storage.direct.asset.call_number.search.record.atomic",
527 my $orgs = { map {$_->owning_lib => 1 } @$vols };
528 return [ keys %$orgs ];
533 __PACKAGE__->register_method(
534 method => "retrieve_copies",
535 api_name => "open-ils.cat.asset.copy_tree.retrieve");
537 __PACKAGE__->register_method(
538 method => "retrieve_copies",
539 api_name => "open-ils.cat.asset.copy_tree.global.retrieve");
541 # user_session may be null/undef
542 sub retrieve_copies {
544 my( $self, $client, $user_session, $docid, @org_ids ) = @_;
546 if(ref($org_ids[0])) { @org_ids = @{$org_ids[0]}; }
550 warn " $$ retrieving copy tree for orgs @org_ids and doc $docid at " . time() . "\n";
552 # grabbing copy trees should be available for everyone..
553 if(!@org_ids and $user_session) {
555 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
556 @org_ids = ($user_obj->home_ou);
559 if( $self->api_name =~ /global/ ) {
560 warn "performing global copy_tree search for $docid\n";
561 return _build_volume_list( { record => $docid } );
566 for my $orgid (@org_ids) {
567 my $vols = _build_volume_list(
568 { record => $docid, owning_lib => $orgid } );
569 warn "Volumes built for org $orgid\n";
570 push( @all_vols, @$vols );
573 warn " $$ Finished copy_tree at " . time() . "\n";
581 sub _build_volume_list {
582 my $search_hash = shift;
584 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
587 my $request = $session->request(
588 "open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
590 my $vols = $request->gather(1);
593 for my $volume (@$vols) {
595 warn "Grabbing copies for volume: " . $volume->id . "\n";
596 my $creq = $session->request(
597 "open-ils.storage.direct.asset.copy.search.call_number.atomic", $volume->id );
599 my $copies = $creq->gather(1);
601 $copies = [ sort { $a->barcode cmp $b->barcode } @$copies ];
603 $volume->copies($copies);
605 push( @volumes, $volume );
609 $session->disconnect();
615 # -----------------------------------------------------------------
616 # Fleshed volume tree batch add/update. This does everything a
617 # volume tree could want, add, update, delete
618 # -----------------------------------------------------------------
619 __PACKAGE__->register_method(
620 method => "volume_tree_fleshed_update",
621 api_name => "open-ils.cat.asset.volume_tree.fleshed.batch.update",
623 sub volume_tree_fleshed_update {
625 my( $self, $client, $user_session, $volumes ) = @_;
626 return undef unless $volumes;
628 my $user_obj = $apputils->check_user_session($user_session);
631 my $session = $apputils->start_db_session();
632 warn "Looping on volumes in fleshed volume tree update\n";
634 # cycle through the volumes provided and update/create/delete where necessary
635 for my $volume (@$volumes) {
637 warn "updating volume " . $volume->id . "\n";
639 my $update_copy_list = $volume->copies;
642 if( $volume->isdeleted) {
643 my $status = _delete_volume($session, $volume, $user_obj);
645 throw OpenSRF::EX::ERROR
646 ("Volume delete failed for volume " . $volume->id);
648 if(UNIVERSAL::isa($status, "Fieldmapper::perm_ex")) { return $status; }
650 } elsif( $volume->isnew ) {
653 $volume->editor($user_obj->id);
654 $volume->creator($user_obj->id);
655 $volume = _add_volume($session, $volume, $user_obj);
658 if($volume and UNIVERSAL::isa($volume, "Fieldmapper::perm_ex")) { return $volume; }
660 } elsif( $volume->ischanged ) {
662 $volume->editor($user_obj->id);
663 my $stat = _update_volume($session, $volume, $user_obj);
664 if($stat and UNIVERSAL::isa($stat, "Fieldmapper::perm_ex")) { return $stat; }
668 if( ! $volume->isdeleted ) {
669 for my $copy (@{$update_copy_list}) {
671 $copy->editor($user_obj->id);
672 warn "updating copy for volume " . $volume->id . "\n";
677 $copy->call_number($volume->id);
678 $copy->creator($user_obj->id);
679 $copy = _fleshed_copy_update($session,$copy,$user_obj);
681 } elsif( $copy->ischanged ) {
682 $copy->call_number($volume->id);
683 $copy = _fleshed_copy_update($session, $copy, $user_obj);
685 } elsif( $copy->isdeleted ) {
686 warn "Deleting copy " . $copy->id . " for volume " . $volume->id . "\n";
687 my $status = _fleshed_copy_update($session, $copy, $user_obj);
688 warn "Copy delete returned a status of $status\n";
694 $apputils->commit_db_session($session);
695 return scalar(@$volumes);
700 my( $session, $volume, $user_obj ) = @_;
702 if($apputils->check_user_perms(
703 $user_obj->id, $user_obj->home_ou, "DELETE_VOLUME")) {
704 return OpenILS::Perm->new("DELETE_VOLUME"); }
706 #$volume = _find_volume($session, $volume);
707 warn "Deleting volume " . $volume->id . "\n";
709 my $copies = $session->request(
710 "open-ils.storage.direct.asset.copy.search.call_number.atomic",
711 $volume->id )->gather(1);
713 throw OpenSRF::EX::ERROR
714 ("Cannot remove volume with copies attached");
717 my $req = $session->request(
718 "open-ils.storage.direct.asset.call_number.delete",
720 return $req->gather(1);
725 my($session, $volume, $user_obj) = @_;
726 if($apputils->check_user_perms(
727 $user_obj->id, $user_obj->home_ou, "UPDATE_VOLUME")) {
728 return OpenILS::Perm->new("UPDATE_VOLUME"); }
730 my $req = $session->request(
731 "open-ils.storage.direct.asset.call_number.update",
733 my $status = $req->gather(1);
738 my($session, $volume, $user_obj) = @_;
740 if($apputils->check_user_perms(
741 $user_obj->id, $user_obj->home_ou, "CREATE_VOLUME")) {
742 warn "User does not have priveleges to create new volumes\n";
743 return OpenILS::Perm->new("CREATE_VOLUME");
746 my $request = $session->request(
747 "open-ils.storage.direct.asset.call_number.create", $volume );
749 my $id = $request->gather(1);
752 OpenILS::Application::AppUtils->rollback_db_session($session);
753 throw OpenSRF::EX::ERROR (" * -> Error creating new volume");
757 warn "received new volume id: $id\n";
765 __PACKAGE__->register_method(
766 method => "fleshed_copy_update",
767 api_name => "open-ils.cat.asset.copy.fleshed.batch.update",
770 sub fleshed_copy_update {
771 my($self, $client, $user_session, $copies) = @_;
773 my $user_obj = $apputils->check_user_session($user_session);
774 my $session = $apputils->start_db_session();
776 for my $copy (@$copies) {
777 _fleshed_copy_update($session, $copy, $user_obj);
780 $apputils->commit_db_session($session);
787 my($session, $copy, $user_obj) = @_;
789 if($apputils->check_user_perms(
790 $user_obj->id, $user_obj->home_ou, "DELETE_COPY")) {
791 return OpenILS::Perm->new("DELETE_COPY"); }
793 warn "Deleting copy " . $copy->id . "\n";
794 my $request = $session->request(
795 "open-ils.storage.direct.asset.copy.delete",
797 return $request->gather(1);
801 my($session, $copy, $user_obj) = @_;
803 if($apputils->check_user_perms(
804 $user_obj->id, $user_obj->home_ou, "CREATE_COPY")) {
805 return OpenILS::Perm->new("CREATE_COPY"); }
807 my $request = $session->request(
808 "open-ils.storage.direct.asset.copy.create",
810 my $id = $request->gather(1);
813 throw OpenSRF::EX::ERROR
814 ("Unable to create new copy " . Dumper($copy));
817 warn "Created copy " . $copy->id . "\n";
824 my($session, $copy, $user_obj) = @_;
826 if($apputils->check_user_perms(
827 $user_obj->id, $user_obj->home_ou, "UPDATE_COPY")) {
828 return OpenILS::Perm->new("UPDATE_COPY"); }
830 my $request = $session->request(
831 "open-ils.storage.direct.asset.copy.update", $copy );
832 my $status = $request->gather(1);
833 warn "Updated copy " . $copy->id . "\n";
838 # -----------------------------------------------------------------
839 # Creates/Updates/Deletes a fleshed asset.copy.
840 # adds/deletes copy stat_cat maps where necessary
841 # -----------------------------------------------------------------
842 sub _fleshed_copy_update {
843 my($session, $copy, $editor) = @_;
845 my $stat_cat_entries = $copy->stat_cat_entries;
846 $copy->editor($editor->id);
848 # in case we're fleshed
849 if(ref($copy->status)) {$copy->status( $copy->status->id ); }
850 if(ref($copy->location)) {$copy->location( $copy->location->id ); }
851 if(ref($copy->circ_lib)) {$copy->circ_lib( $copy->circ_lib->id ); }
853 warn "Updating copy " . Dumper($copy) . "\n";
855 if( $copy->isdeleted ) {
856 return _delete_copy($session, $copy, $editor);
857 } elsif( $copy->isnew ) {
858 $copy = _create_copy($session, $copy, $editor);
859 } elsif( $copy->ischanged ) {
860 _update_copy($session, $copy, $editor);
864 if(!@$stat_cat_entries) { return 1; }
866 my $stat_maps = $session->request(
867 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.search.owning_copy.atomic",
868 $copy->id )->gather(1);
870 if(!$copy->isnew) { _delete_stale_maps($session, $stat_maps, $copy); }
872 # go through the stat cat update/create process
873 for my $stat_entry (@{$stat_cat_entries}){
874 _copy_update_stat_cats( $session, $copy, $stat_maps, $stat_entry, $editor );
881 # -----------------------------------------------------------------
882 # Deletes stat maps attached to this copy in the database that
883 # are no longer attached to the current copy
884 # -----------------------------------------------------------------
885 sub _delete_stale_maps {
886 my( $session, $stat_maps, $copy) = @_;
888 warn "Deleting stale stat maps for copy " . $copy->id . "\n";
889 for my $map (@$stat_maps) {
890 # if there is no stat cat entry on the copy who's id matches the
891 # current map's id, remove the map from the database
892 if(! grep { $_->id == $map->stat_cat_entry } @{$copy->stat_cat_entries} ) {
893 my $req = $session->request(
894 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.delete", $map );
903 # -----------------------------------------------------------------
904 # Searches the stat maps to see if '$entry' already exists on
905 # the given copy. If it does not, a new stat map is created
906 # for the given entry and copy
907 # -----------------------------------------------------------------
908 sub _copy_update_stat_cats {
909 my ( $session, $copy, $stat_maps, $entry, $editor ) = @_;
911 warn "Updating stat maps for copy " . $copy->id . "\n";
913 # see if this map already exists
914 for my $map (@$stat_maps) {
915 if( $map->stat_cat_entry == $entry->id ) {return;}
918 warn "Creating new stat map for stat " .
919 $entry->stat_cat . " and copy " . $copy->id . "\n";
922 my $new_map = Fieldmapper::asset::stat_cat_entry_copy_map->new();
924 $new_map->stat_cat( $entry->stat_cat );
925 $new_map->stat_cat_entry( $entry->id );
926 $new_map->owning_copy( $copy->id );
928 warn "New map is " . Dumper($new_map) . "\n";
930 my $request = $session->request(
931 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.create",
933 my $status = $request->gather(1);
934 warn "created new map with id $status\n";