]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Cat.pm
small tweaks, see diffs
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Cat.pm
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);
9 use JSON;
10 use OpenILS::Utils::Fieldmapper;
11 use XML::LibXML;
12 use Data::Dumper;
13 use OpenILS::Utils::FlatXML;
14
15 my $apputils = "OpenILS::Application::AppUtils";
16
17 my $utils = "OpenILS::Application::Cat::Utils";
18
19
20 __PACKAGE__->register_method(
21         method  => "biblio_record_tree_import",
22         api_name        => "open-ils.cat.biblio.record.tree.import",
23 );
24
25 sub biblio_record_tree_import {
26         my( $self, $client, $user_session, $tree) = @_;
27         my $user_obj = $apputils->check_user_session($user_session);
28
29         warn "importing new record " . Dumper($tree) . "\n";
30
31         my $nodeset = $utils->tree2nodeset($tree);
32         warn "turned into nodeset " . Dumper($nodeset) . "\n";
33
34         # copy the doc so that we can mangle the namespace.  
35         my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml($nodeset);
36         my $copy_marcxml = XML::LibXML->new->parse_string($marcxml->toString);
37
38         $marcxml->documentElement->setNamespace( "http://www.loc.gov/MARC21/slim", "marc", 1 );
39         my $tcn;
40
41
42         warn "Starting db session in import\n";
43         my $session = $apputils->start_db_session();
44         my $source = 2; # system local source
45
46         my $xpath = '//controlfield[@tag="001"]';
47         $tcn = $marcxml->documentElement->findvalue($xpath);
48         if(_tcn_exists($session, $tcn)) {$tcn = undef;}
49         my $tcn_source = "External";
50
51
52         if(!$tcn) {
53                 $xpath = '//datafield[@tag="020"]';
54                 $tcn = $marcxml->documentElement->findvalue($xpath);
55                 $tcn_source = "ISBN";
56                 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
57         }
58
59         if(!$tcn) { 
60                 $xpath = '//datafield[@tag="022"]';
61                 $tcn = $marcxml->documentElement->findvalue($xpath);
62                 $tcn_source = "ISSN";
63                 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
64         }
65
66         if(!$tcn) {
67                 $xpath = '//datafield[@tag="010"]';
68                 $tcn = $marcxml->documentElement->findvalue($xpath);
69                 $tcn_source = "LCCN";
70                 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
71         }
72
73         if(!$tcn) {
74                 $xpath = '//datafield[@tag="035"]';
75                 $tcn = $marcxml->documentElement->findvalue($xpath);
76                 $tcn_source = "System";
77                 if(_tcn_exists($session, $tcn)) {$tcn = undef;}
78         }
79
80         warn "Record import with tcn: $tcn and source $tcn_source\n";
81
82         my $record = Fieldmapper::biblio::record_entry->new;
83
84         $record->source($source);
85         $record->tcn_source($tcn_source);
86         $record->tcn_value($tcn);
87         $record->creator($user_obj->id);
88         $record->editor($user_obj->id);
89         $record->marc($copy_marcxml->toString);
90
91
92         my $req = $session->request(
93                 "open-ils.storage.direct.biblio.record_entry.create",
94                 $record );
95         my $id = $req->gather(1);
96
97         my $wreq = $session->request("open-ils.worm.wormize", $id);
98         $wreq->gather(1);
99
100         $apputils->commit_db_session($session);
101
102         return $self->biblio_record_tree_retrieve($client, $id);
103 }
104
105 sub _tcn_exists {
106         my $session = shift;
107         my $tcn = shift;
108
109         if(!$tcn) {return 0;}
110
111         my $req = $session->request(      
112                 "open-ils.storage.direct.biblio.record_entry.search.tcn_value.atomic",
113                 $tcn );
114         my $recs = $req->gather(1);
115
116         if($recs and $recs->[0]) {
117                 return 1;
118         }
119         return 0;
120 }
121
122
123
124 __PACKAGE__->register_method(
125         method  => "biblio_record_tree_retrieve",
126         api_name        => "open-ils.cat.biblio.record.tree.retrieve",
127 );
128
129 sub biblio_record_tree_retrieve {
130
131         my( $self, $client, $recordid ) = @_;
132
133         my $name = "open-ils.storage.direct.biblio.record_entry.retrieve";
134         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
135         my $request = $session->request( $name, $recordid );
136         my $marcxml = $request->gather(1);
137
138         if(!$marcxml) {
139                 throw OpenSRF::EX::ERROR 
140                         ("No record in database with id $recordid");
141         }
142
143         $session->disconnect();
144         $session->kill_me();
145
146         warn "turning into nodeset\n";
147         my $nodes = OpenILS::Utils::FlatXML->new()->xml_to_nodeset( $marcxml->marc ); 
148         warn "turning nodeset into tree\n";
149         my $tree = $utils->nodeset2tree( $nodes->nodeset );
150
151         $tree->owner_doc( $marcxml->id() );
152
153         warn "returning tree\n";
154
155         return $tree;
156 }
157
158 __PACKAGE__->register_method(
159         method  => "biblio_record_tree_commit",
160         api_name        => "open-ils.cat.biblio.record.tree.commit",
161         argc            => 3, #(session_id, biblio_tree ) 
162         note            => "Walks the tree and commits any changed nodes " .
163                                         "adds any new nodes, and deletes any deleted nodes",
164 );
165
166 sub biblio_record_tree_commit {
167
168         my( $self, $client, $user_session,  $tree ) = @_;
169
170         throw OpenSRF::EX::InvalidArg 
171                 ("Not enough args to to open-ils.cat.biblio.record.tree.commit")
172                 unless ( $user_session and $tree );
173
174         my $user_obj = 
175                 OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
176
177         # capture the doc id
178         my $docid = $tree->owner_doc();
179         my $session = OpenILS::Application::AppUtils->start_db_session();
180
181         warn "Retrieving biblio record from storage for update\n";
182
183         my $req1 = $session->request(
184                         "open-ils.storage.direct.biblio.record_entry.batch.retrieve", 
185                         $docid );
186         my $biblio = $req1->gather(1);
187
188         warn "retrieved doc $docid\n";
189
190
191         # turn the tree into a nodeset
192         my $nodeset = $utils->tree2nodeset($tree);
193         $nodeset = $utils->clean_nodeset($nodeset);
194
195         if(!defined($docid)) { # be sure
196                 for my $node (@$nodeset) {
197                         $docid = $node->owner_doc();
198                         last if defined($docid);
199                 }
200         }
201
202         # turn the nodeset into a doc
203         my $marcxml = OpenILS::Utils::FlatXML->new()->nodeset_to_xml( $nodeset );
204
205         $biblio->marc( $marcxml->toString() );
206
207         warn "Starting db session\n";
208
209         my $x = _update_record_metadata( $session, { user => $user_obj, docid => $docid } );
210         OpenILS::Application::AppUtils->rollback_db_session($session) unless $x;
211
212         warn "Sending updated doc $docid to db\n";
213         my $req = $session->request( "open-ils.storage.direct.biblio.record_entry.update", $biblio );
214
215         $req->wait_complete;
216         my $status = $req->recv();
217         if( !$status || $status->isa("Error") || ! $status->content) {
218                 OpenILS::Application::AppUtils->rollback_db_session($session);
219                 if($status->isa("Error")) { throw $status ($status); }
220                 throw OpenSRF::EX::ERROR ("Error updating biblio record");
221         }
222         $req->finish();
223
224         # Send the doc to the wormer for wormizing
225         warn "Starting worm session\n";
226
227         my $success = 0;
228         my $wresp;
229
230         my $wreq = $session->request( "open-ils.worm.wormize", $docid );
231
232         try {
233                 $wreq->gather(1);
234
235         } catch Error with {
236                 my $e = shift;
237                 warn "wormizing failed, rolling back\n";
238                 OpenILS::Application::AppUtils->rollback_db_session($session);
239
240                 if($e) { throw $e ($e); }
241                 throw OpenSRF::EX::ERROR ("Wormizing Failed for $docid" );
242         };
243
244         warn "Committing db session...\n";
245         OpenILS::Application::AppUtils->commit_db_session( $session );
246
247         $nodeset = OpenILS::Utils::FlatXML->new()->xmldoc_to_nodeset($marcxml);
248         $tree = $utils->nodeset2tree($nodeset->nodeset);
249         $tree->owner_doc($docid);
250
251 #       $client->respond_complete($tree);
252
253         warn "Done wormizing\n";
254
255         #use Data::Dumper;
256         #warn "Returning tree:\n";
257         #warn Dumper $tree;
258
259         return $tree;
260
261 }
262
263
264
265 __PACKAGE__->register_method(
266         method  => "biblio_record_record_metadata",
267         api_name        => "open-ils.cat.biblio.record.metadata.retrieve",
268         argc            => 1, #(session_id, biblio_tree ) 
269         note            => "Walks the tree and commits any changed nodes " .
270                                         "adds any new nodes, and deletes any deleted nodes",
271 );
272
273 sub biblio_record_record_metadata {
274         my( $self, $client, @ids ) = @_;
275
276         if(!@ids){return undef;}
277
278         my $session = OpenSRF::AppSession->create("open-ils.storage");
279         my $request = $session->request( 
280                         "open-ils.storage.direct.biblio.record_entry.batch.retrieve", @ids );
281
282         my $results = [];
283
284         while( my $response = $request->recv() ) {
285
286                 if(!$response) {
287                         throw OpenSRF::EX::ERROR ("No Response from Storage");
288                 }
289                 if($response->isa("Error")) {
290                         throw $response ($response->stringify);
291                 }
292
293                 my $record_entry = $response->content;
294
295                 my $creator = $record_entry->creator;
296                 my $editor      = $record_entry->editor;
297
298                 ($creator, $editor) = _get_userid_by_id($creator, $editor);
299
300                 $record_entry->creator( $creator );
301                 $record_entry->editor( $editor );
302
303                 push @$results, $record_entry;
304
305         }
306
307         $request->finish;
308         $session->disconnect();
309         $session->finish();
310
311         return $results;
312
313 }
314
315 # gets the username
316 sub _get_userid_by_id {
317
318         my @ids = @_;
319         my @users;
320
321         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
322         my $request = $session->request( 
323                 "open-ils.storage.direct.actor.user.batch.retrieve.atomic", @ids );
324
325         $request->wait_complete;
326         my $response = $request->recv();
327         if(!$request->complete) { return undef; }
328
329         if($response->isa("Error")){
330                 throw $response ($response);
331         }
332
333         for my $u (@{$response->content}) {
334                 next unless ref($u);
335                 push @users, $u->usrname;
336         }
337
338         $request->finish;
339         $session->disconnect;
340         $session->kill_me();
341
342         return @users;
343 }
344
345 sub _get_id_by_userid {
346
347         my @users = @_;
348         my @ids;
349
350         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
351         my $request = $session->request( 
352                 "open-ils.storage.direct.actor.user.search.usrname.atomic", @users );
353
354         $request->wait_complete;
355         my $response = $request->recv();
356         if(!$request->complete) { 
357                 throw OpenSRF::EX::ERROR ("no response from storage on user retrieve");
358         }
359
360         if(UNIVERSAL::isa( $response, "Error")){
361                 throw $response ($response);
362         }
363
364         for my $u (@{$response->content}) {
365                 next unless ref($u);
366                 push @ids, $u->id();
367         }
368
369         $request->finish;
370         $session->disconnect;
371         $session->kill_me();
372
373         return @ids;
374 }
375
376
377 # commits metadata objects to the db
378 sub _update_record_metadata {
379
380         my ($session, @docs ) = @_;
381
382         for my $doc (@docs) {
383
384                 my $user_obj = $doc->{user};
385                 my $docid = $doc->{docid};
386
387                 warn "Updating metata for doc $docid\n";
388
389                 my $request = $session->request( 
390                         "open-ils.storage.direct.biblio.record_entry.retrieve", $docid );
391                 my $record = $request->gather(1);
392
393                 warn "retrieved record\n";
394                 my ($id) = _get_id_by_userid($user_obj->usrname);
395
396                 warn "got $id from _get_id_by_userid\n";
397                 $record->editor($id);
398                 
399                 warn "Grabbed the record, updating and moving on\n";
400
401                 $request = $session->request( 
402                         "open-ils.storage.direct.biblio.record_entry.update", $record );
403                 $request->gather(1);
404         }
405
406         warn "committing metarecord update\n";
407
408         return 1;
409 }
410
411
412
413 __PACKAGE__->register_method(
414         method  => "orgs_for_title",
415         api_name        => "open-ils.cat.actor.org_unit.retrieve_by_title"
416 );
417
418 sub orgs_for_title {
419         my( $self, $client, $record_id ) = @_;
420
421         my $vols = $apputils->simple_scalar_request(
422                 "open-ils.storage",
423                 "open-ils.storage.direct.asset.call_number.search.record.atomic",
424                 $record_id );
425
426         my $orgs = { map {$_->owning_lib => 1 } @$vols };
427         return [ keys %$orgs ];
428 }
429
430
431
432 __PACKAGE__->register_method(
433         method  => "retrieve_copies",
434         api_name        => "open-ils.cat.asset.copy_tree.retrieve");
435
436 __PACKAGE__->register_method(
437         method  => "retrieve_copies",
438         api_name        => "open-ils.cat.asset.copy_tree.global.retrieve");
439
440 # user_session may be null/undef
441 sub retrieve_copies {
442
443         my( $self, $client, $user_session, $docid, @org_ids ) = @_;
444
445         if(ref($org_ids[0])) { @org_ids = @{$org_ids[0]}; }
446
447         $docid = "$docid";
448
449         warn " $$ retrieving copy tree for orgs @org_ids and doc $docid at " . time() . "\n";
450
451         # grabbing copy trees should be available for everyone..
452         if(!@org_ids and $user_session) {
453                 my $user_obj = 
454                         OpenILS::Application::AppUtils->check_user_session( $user_session ); #throws EX on error
455                         @org_ids = ($user_obj->home_ou);
456         }
457
458         if( $self->api_name =~ /global/ ) {
459                 warn "performing global copy_tree search for $docid\n";
460                 return _build_volume_list( { record => $docid } );
461
462         } else {
463
464                 my @all_vols;
465                 for my $orgid (@org_ids) {
466                         my $vols = _build_volume_list( 
467                                         { record => $docid, owning_lib => $orgid } );
468                         warn "Volumes built for org $orgid\n";
469                         push( @all_vols, @$vols );
470                 }
471                 
472                 warn " $$ Finished copy_tree at " . time() . "\n";
473                 return \@all_vols;
474         }
475
476         return undef;
477 }
478
479
480 sub _build_volume_list {
481         my $search_hash = shift;
482
483         my      $session = OpenSRF::AppSession->create( "open-ils.storage" );
484         
485
486         my $request = $session->request( 
487                         "open-ils.storage.direct.asset.call_number.search.atomic", $search_hash );
488
489         my $vols = $request->gather(1);
490         my @volumes;
491
492         for my $volume (@$vols) {
493
494                 warn "Grabbing copies for volume: " . $volume->id . "\n";
495                 my $creq = $session->request(
496                         "open-ils.storage.direct.asset.copy.search.call_number.atomic", 
497                         $volume->id );
498                 my $copies = $creq->gather(1);
499
500                 $volume->copies($copies);
501
502                 push( @volumes, $volume );
503         }
504
505
506         $session->disconnect();
507         return \@volumes;
508
509 }
510
511
512 # -----------------------------------------------------------------
513 # Fleshed volume tree batch add/update.  This does everything a 
514 # volume tree could want, add, update, delete
515 # -----------------------------------------------------------------
516 __PACKAGE__->register_method(
517         method  => "volume_tree_fleshed_update",
518         api_name        => "open-ils.cat.asset.volume_tree.fleshed.batch.update",
519 );
520 sub volume_tree_fleshed_update {
521
522         my( $self, $client, $user_session, $volumes ) = @_;
523         return undef unless $volumes;
524         my $user_obj = $apputils->check_user_session($user_session);
525
526         my $session = $apputils->start_db_session();
527         warn "Looping on volumes in fleshed volume tree update\n";
528
529         # cycle through the volumes provided and update/create/delete where necessary
530         for my $volume (@$volumes) {
531
532                 warn "updating volume " . $volume->id . "\n";
533
534                 my $update_copy_list = $volume->copies;
535
536
537                 if( $volume->isdeleted) {
538                         my $status = _delete_volume($session, $volume);
539                         if(!$status) {
540                                 throw OpenSRF::EX::ERROR
541                                         ("Volume delete failed for volume " . $volume->id);
542                         }
543
544                 } elsif( $volume->isnew ) {
545
546                         $volume->clear_id;
547                         $volume->editor($user_obj->id);
548                         $volume->creator($user_obj->id);
549                         $volume = _add_volume($session, $volume);
550
551                 } elsif( $volume->ischanged ) {
552
553                         $volume->editor($user_obj->id);
554                         _update_volume($session, $volume);
555                 }
556
557
558                 if( ! $volume->isdeleted ) {
559                         for my $copy (@{$update_copy_list}) {
560         
561                                 $copy->editor($user_obj->id);
562                                 warn "updating copy for volume " . $volume->id . "\n";
563         
564                                 if( $copy->isnew ) {
565         
566                                         $copy->clear_id;
567                                         $copy->call_number($volume->id);
568                                         $copy->creator($user_obj->id);
569                                         $copy = _fleshed_copy_update($session,$copy,$user_obj->id);
570         
571                                 } elsif( $copy->ischanged ) {
572                                         $copy->call_number($volume->id);
573                                         $copy = _fleshed_copy_update($session, $copy, $user_obj->id);
574         
575                                 } elsif( $copy->isdeleted ) {
576                                         warn "Deleting copy " . $copy->id . " for volume " . $volume->id . "\n";
577                                         my $status = _fleshed_copy_update($session, $copy, $user_obj->id);
578                                         warn "Copy delete returned a status of $status\n";
579                                 }
580                         }
581                 }
582         }
583         $apputils->commit_db_session($session);
584         return scalar(@$volumes);
585 }
586
587
588 sub _delete_volume {
589         my( $session, $volume ) = @_;
590
591         #$volume = _find_volume($session, $volume);
592         warn "Deleting volume " . $volume->id . "\n";
593
594         my $copies = $session->request(
595                 "open-ils.storage.direct.asset.copy.search.call_number.atomic",
596                 $volume->id )->gather(1);
597         if(@$copies) {
598                 throw OpenSRF::EX::ERROR 
599                         ("Cannot remove volume with copies attached");
600         }
601
602         my $req = $session->request(
603                 "open-ils.storage.direct.asset.call_number.delete",
604                 $volume );
605         return $req->gather(1);
606 }
607
608
609 sub _update_volume {
610         my($session, $volume) = @_;
611         my $req = $session->request(
612                 "open-ils.storage.direct.asset.call_number.update",
613                 $volume );
614         my $status = $req->gather(1);
615 }
616
617 sub _add_volume {
618
619         my($session, $volume) = @_;
620
621         my $request = $session->request( 
622                 "open-ils.storage.direct.asset.call_number.create", $volume );
623
624         my $id = $request->gather(1);
625
626         if( $id == 0 ) {
627                 OpenILS::Application::AppUtils->rollback_db_session($session);
628                 throw OpenSRF::EX::ERROR (" * -> Error creating new volume");
629         }
630
631         $volume->id($id);
632         warn "received new volume id: $id\n";
633         return $volume;
634
635 }
636
637
638
639
640 __PACKAGE__->register_method(
641         method  => "fleshed_copy_update",
642         api_name        => "open-ils.cat.asset.copy.fleshed.batch.update",
643 );
644
645 sub fleshed_copy_update {
646         my($self, $client, $user_session, $copies) = @_;
647
648         my $user_obj = $apputils->check_user_session($user_session); 
649         my $session = $apputils->start_db_session();
650
651         for my $copy (@$copies) {
652                 _fleshed_copy_update($session, $copy, $user_obj->id);
653         }
654
655         $apputils->commit_db_session($session);
656         return 1;
657 }
658
659
660
661 sub _delete_copy {
662         my($session, $copy) = @_;
663         warn "Deleting copy " . $copy->id . "\n";
664         my $request = $session->request(
665                 "open-ils.storage.direct.asset.copy.delete",
666                 $copy );
667         return $request->gather(1);
668 }
669
670 sub _create_copy {
671         my($session, $copy) = @_;
672
673         my $request = $session->request(
674                 "open-ils.storage.direct.asset.copy.create",
675                 $copy );
676         my $id = $request->gather(1);
677
678         if($id < 1) {
679                 throw OpenSRF::EX::ERROR
680                         ("Unable to create new copy " . Dumper($copy));
681         }
682         $copy->id($id);
683         warn "Created copy " . $copy->id . "\n";
684
685         return $copy;
686
687 }
688
689 sub _update_copy {
690         my($session, $copy) = @_;
691         my $request = $session->request(
692                 "open-ils.storage.direct.asset.copy.update", $copy );
693         my $status = $request->gather(1);
694         warn "Updated copy " . $copy->id . "\n";
695         return $status;
696 }
697
698
699 # -----------------------------------------------------------------
700 # Creates/Updates/Deletes a fleshed asset.copy.  
701 # adds/deletes copy stat_cat maps where necessary
702 # -----------------------------------------------------------------
703 sub _fleshed_copy_update {
704         my($session, $copy, $editor) = @_;
705
706         my $stat_cat_entries = $copy->stat_cat_entries;
707         $copy->editor($editor);
708         
709         # in case we're fleshed
710         if(ref($copy->status))          {$copy->status( $copy->status->id ); }
711         if(ref($copy->location))        {$copy->location( $copy->location->id ); }
712         if(ref($copy->circ_lib))        {$copy->circ_lib( $copy->circ_lib->id ); }
713
714         warn "Updating copy " . Dumper($copy) . "\n";
715
716         if( $copy->isdeleted ) { 
717                 return _delete_copy($session, $copy);
718         } elsif( $copy->isnew ) {
719                 $copy = _create_copy($session, $copy);
720         } elsif( $copy->ischanged ) {
721                 _update_copy($session, $copy);
722         }
723
724         
725         if(!@$stat_cat_entries) { return 1; }
726
727         my $stat_maps = $session->request(
728                 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.search.owning_copy.atomic",
729                 $copy->id )->gather(1);
730
731         if(!$copy->isnew) { _delete_stale_maps($session, $stat_maps, $copy); }
732         
733         # go through the stat cat update/create process
734         for my $stat_entry (@{$stat_cat_entries}){ 
735                 _copy_update_stat_cats( $session, $copy, $stat_maps, $stat_entry );
736         }
737         
738         return 1;
739 }
740
741
742 # -----------------------------------------------------------------
743 # Deletes stat maps attached to this copy in the database that
744 # are no longer attached to the current copy
745 # -----------------------------------------------------------------
746 sub _delete_stale_maps {
747         my( $session, $stat_maps, $copy) = @_;
748
749         warn "Deleting stale stat maps for copy " . $copy->id . "\n";
750         for my $map (@$stat_maps) {
751         # if there is no stat cat entry on the copy who's id matches the
752         # current map's id, remove the map from the database
753         if(! grep { $_->id == $map->stat_cat_entry } @{$copy->stat_cat_entries} ) {
754                 my $req = $session->request(
755                         "open-ils.storage.direct.asset.stat_cat_entry_copy_map.delete", $map );
756                 $req->gather(1);
757                 }
758         }
759
760         return $stat_maps;
761 }
762
763
764 # -----------------------------------------------------------------
765 # Searches the stat maps to see if '$entry' already exists on
766 # the given copy.  If it does not, a new stat map is created
767 # for the given entry and copy
768 # -----------------------------------------------------------------
769 sub _copy_update_stat_cats {
770         my ( $session, $copy, $stat_maps, $entry ) = @_;
771
772         warn "Updating stat maps for copy " . $copy->id . "\n";
773
774         # see if this map already exists
775         for my $map (@$stat_maps) {
776                 if( $map->stat_cat_entry == $entry->id ) {return;}
777         }
778
779         warn "Creating new stat map for stat  " . 
780                 $entry->stat_cat . " and copy " . $copy->id . "\n";
781
782         # if not, create it
783         my $new_map = Fieldmapper::asset::stat_cat_entry_copy_map->new();
784
785         $new_map->stat_cat( $entry->stat_cat );
786         $new_map->stat_cat_entry( $entry->id );
787         $new_map->owning_copy( $copy->id );
788
789         warn "New map is " . Dumper($new_map) . "\n";
790
791         my $request = $session->request(
792                 "open-ils.storage.direct.asset.stat_cat_entry_copy_map.create",
793                 $new_map );
794         my $status = $request->gather(1);
795         warn "created new map with id $status\n";
796
797 }
798
799
800
801
802 1;