]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/asset.pm
initial holdings importer
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / Publisher / asset.pm
1 package OpenILS::Application::Storage::Publisher::asset;
2 use base qw/OpenILS::Application::Storage/;
3 #use OpenILS::Application::Storage::CDBI::asset;
4 #use OpenSRF::Utils::Logger qw/:level/;
5 #use OpenILS::Utils::Fieldmapper;
6 #
7 #my $log = 'OpenSRF::Utils::Logger';
8
9 use MARC::Record;
10 use MARC::File::XML;
11
12 #our $_default_subfield_map = {
13 #        call_number     => $cn,
14 #        barcode         => $bc,
15 #        owning_lib      => $ol,
16 #        circulating_lib => $cl,
17 #        copy_location   => $sl,
18 #        copy_number     => $num,
19 #        price           => $pr,
20 #        status          => $loc,
21 #        create_date     => $date,
22 #
23 #        legacy_item_type        => $it,
24 #        legacy_item_cat_1       => $ic1,
25 #        legacy_item_cat_2       => $ic2,
26 #};
27
28 sub import_xml_holdings {
29         my $self = shift;
30         my $client = shift;
31         my $editor = shift;
32         my $record = shift;
33         my $xml = shift;
34         my $tag = shift;
35         my $map = shift;
36         my $date_format = shift || 'mm/dd/yyyy';
37
38         my $r = MARC::Record->new_from_xml($xml);
39
40         for my $f ( $r->fields( $tag ) ) {
41                 next unless ($f->subfield( $map->{owning_lib} ));
42
43                 my $ol = actor::org_unit->search( shortname => $f->subfield( $map->{owning_lib} ) )->next->id;
44                 my $cl = actor::org_unit->search( shortname => $f->subfield( $map->{circulating_lib} ) )->next->id;
45
46                 my $cn = asset::call_number->find_or_create(
47                         { label         => $f->subfield( $map->{call_number} ),
48                           owning_lib    => $ol,
49                           record        => $record,
50                           creator       => $editor,
51                           editor        => $editor,
52                         }
53                 );
54
55                 my $create_date =  $f->subfield( $map->{create_date} );
56
57                 my ($m,$d,$y);
58                 if ($date_format eq 'mm/dd/yyyy') {
59                         ($m,$d,$y) = split '/', $create_date;
60
61                 } elsif ($date_format eq 'dd/mm/yyyy') {
62                         ($d,$m,$y) = split '/', $create_date;
63
64                 } elsif ($date_format eq 'mm-dd-yyyy') {
65                         ($m,$d,$y) = split '-', $create_date;
66
67                 } elsif ($date_format eq 'dd-mm-yyyy') {
68                         ($d,$m,$y) = split '-', $create_date;
69
70                 } elsif ($date_format eq 'yyyy-mm-dd') {
71                         ($y,$m,$d) = split '-', $create_date;
72
73                 } elsif ($date_format eq 'yyyy/mm/dd') {
74                         ($y,$m,$d) = split '-', $create_date;
75                 }
76
77                 my $price = $f->subfield( $map->{price} );
78                 $price =~ s/[^0-9\.]+//gso;
79                 $price ||= '0.00';
80
81                 $cn->add_to_copies(
82                         { circ_lib      => actor::org_unit->search( shortname => $f->subfield( $map->{circulating_lib} ) )->next->id,
83                           copy_number   => $f->subfield( $map->{copy_number} ),
84                           price         => $price,
85                           barcode       => $f->subfield( $map->{barcode} ),
86                           loan_duration => 2,
87                           fine_level    => 2,
88                           creator       => $editor,
89                           editor        => $editor,
90                           create_date   => sprintf('%04d-%02d-%02d',$y,$m,$d),
91                         }
92                 );
93         }
94
95         return 1;
96 }
97 __PACKAGE__->register_method(
98         method          => 'import_xml_holdings',
99         api_name        => 'open-ils.storage.asset.holdings.import.xml',
100         argc            => 5,
101         stream          => 0,
102 );
103
104 # XXX
105 # see /home/miker/cn_browse-test.sql for page up and down sql ...
106 # XXX
107
108 sub cn_browse_pagedown {
109         my $self = shift;
110         my $client = shift;
111
112         my %args = @_;
113
114         my $cn = uc($args{label});
115         my $org = $args{org_unit};
116         my $depth = $args{depth};
117         my $boundry_id = $args{boundry_id};
118         my $size = $args{page_size} || 20;
119         $size = int($size);
120
121         my $table = asset::call_number->table;
122
123         my $descendants = "actor.org_unit_descendants($org)";
124         if (defined $depth) {
125                 $descendants = "actor.org_unit_descendants($org,$depth)";
126         }
127
128         my $sql = <<"   SQL";
129                 select
130                         cn.label,
131                         cn.owning_lib,
132                         cn.record,
133                         cn.id
134                 from
135                         $table cn
136                         join $descendants d
137                                 on (d.id = cn.owning_lib)
138                 where
139                         upper(label) > ?
140                         or ( cn.id > ? and upper(label) = ? )
141                 order by upper(label), 4, 2
142                 limit $size;
143         SQL
144
145         my $sth = asset::call_number->db_Main->prepare($sql);
146         $sth->execute($cn, $boundry_id, $cn);
147         while ( my @row = $sth->fetchrow_array ) {
148                 $client->respond([@row]);
149         }
150         $sth->finish;
151
152         return undef;
153 }
154 __PACKAGE__->register_method(
155         method          => 'cn_browse_pagedown',
156         api_name        => 'open-ils.storage.asset.call_number.browse.page_down',
157         argc            => 4,
158         stream          => 1,
159 );
160
161 sub cn_browse_pageup {
162         my $self = shift;
163         my $client = shift;
164
165         my %args = @_;
166
167         my $cn = uc($args{label});
168         my $org = $args{org_unit};
169         my $depth = $args{depth};
170         my $boundry_id = $args{boundry_id};
171         my $size = $args{page_size} || 20;
172         $size = int($size);
173
174         my $table = asset::call_number->table;
175
176         my $descendants = "actor.org_unit_descendants($org)";
177         if (defined $depth) {
178                 $descendants = "actor.org_unit_descendants($org,$depth)";
179         }
180
181         my $sql = <<"   SQL";
182                 select * from (
183                         select
184                                 cn.label,
185                                 cn.owning_lib,
186                                 cn.record,
187                                 cn.id
188                         from
189                                 $table cn
190                                 join $descendants d
191                                         on (d.id = cn.owning_lib)
192                         where
193                                 upper(label) < ?
194                                 or ( cn.id < ? and upper(label) = ? )
195                         order by upper(label) desc, 4 desc, 2 desc
196                         limit $size
197                 ) as bar
198                 order by 1,4,2;
199         SQL
200
201         my $sth = asset::call_number->db_Main->prepare($sql);
202         $sth->execute($cn, $boundry_id, $cn);
203         while ( my @row = $sth->fetchrow_array ) {
204                 $client->respond([@row]);
205         }
206         $sth->finish;
207
208         return undef;
209 }
210 __PACKAGE__->register_method(
211         method          => 'cn_browse_pageup',
212         api_name        => 'open-ils.storage.asset.call_number.browse.page_up',
213         argc            => 4,
214         stream          => 1,
215 );
216
217 sub cn_browse_target {
218         my $self = shift;
219         my $client = shift;
220
221         my %args = @_;
222
223         my $cn = uc($args{label});
224         my $org = $args{org_unit};
225         my $depth = $args{depth};
226         my $size = $args{page_size} || 20;
227         my $topsize = $size / 2;
228         $topsize = int($topsize);
229         $bottomsize = $size - $topsize;
230
231         my $table = asset::call_number->table;
232
233         my $descendants = "actor.org_unit_descendants($org)";
234         if (defined $depth) {
235                 $descendants = "actor.org_unit_descendants($org,$depth)";
236         }
237
238         my $top_sql = <<"       SQL";
239                 select * from (
240                         select
241                                 cn.label,
242                                 cn.owning_lib,
243                                 cn.record,
244                                 cn.id
245                         from
246                                 $table cn
247                                 join $descendants d
248                                         on (d.id = cn.owning_lib)
249                         where
250                                 upper(label) < ?
251                         order by upper(label) desc, 4 desc, 2 desc
252                         limit $topsize
253                 ) as bar
254                 order by 1,4,2;
255         SQL
256
257         my $bottom_sql = <<"    SQL";
258                 select
259                         cn.label,
260                         cn.owning_lib,
261                         cn.record,
262                         cn.id
263                 from
264                         $table cn
265                         join $descendants d
266                                 on (d.id = cn.owning_lib)
267                 where
268                         upper(label) >= ?
269                 order by upper(label),4,2
270                 limit $bottomsize;
271         SQL
272
273         my $sth = asset::call_number->db_Main->prepare($top_sql);
274         $sth->execute($cn);
275         while ( my @row = $sth->fetchrow_array ) {
276                 $client->respond([@row]);
277         }
278         $sth->finish;
279
280         $sth = asset::call_number->db_Main->prepare($bottom_sql);
281         $sth->execute($cn);
282         while ( my @row = $sth->fetchrow_array ) {
283                 $client->respond([@row]);
284         }
285         $sth->finish;
286
287         return undef;
288 }
289 __PACKAGE__->register_method(
290         method          => 'cn_browse_target',
291         api_name        => 'open-ils.storage.asset.call_number.browse.target',
292         argc            => 4,
293         stream          => 1,
294 );
295
296
297 sub copy_proximity {
298         my $self = shift;
299         my $client = shift;
300
301         my $cp = shift;
302         my $org = shift;
303
304         return unless ($cp && $org);
305
306         $cp = $cp->id if (ref $cp);
307         $cp = asset::copy->retrieve($cp);
308         return unless $copy;
309         my $ol = $cp->call_number->owning_lib;
310
311         return asset::copy->db_Main->selectcol_arrayref('SELECT actor.org_unit_proximity(?,?)',{},"$ol","$org")->[0];
312 }
313 __PACKAGE__->register_method(
314         method          => 'copy_proximity',
315         api_name        => 'open-ils.storage.asset.copy.proximity',
316         argc            => 2,
317         stream          => 1,
318 );
319
320 sub asset_copy_location_all {
321         my $self = shift;
322         my $client = shift;
323
324         for my $rec ( asset::copy_location->retrieve_all ) {
325                 $client->respond( $rec->to_fieldmapper );
326         }
327
328         return undef;
329 }
330 __PACKAGE__->register_method(
331         method          => 'asset_copy_location_all',
332         api_name        => 'open-ils.storage.direct.asset.copy_location.retrieve.all',
333         argc            => 0,
334         stream          => 1,
335 );
336
337 # XXX arg, with the descendancy SPs...
338 sub ranged_asset_copy_location {
339         my $self = shift;
340         my $client = shift;
341         my @binds = @_;
342         
343         my $ctable = asset::copy_location->table;
344         
345         my $descendants = defined($binds[1]) ?
346                 "actor.org_unit_full_path(?, ?)" :
347                 "actor.org_unit_full_path(?)" ;
348
349         
350         my $sql = <<"   SQL";
351                 SELECT  DISTINCT c.*
352                   FROM  $ctable c
353                         JOIN $descendants d
354                                 ON (d.id = c.owning_lib)
355         SQL
356         
357         my $sth = asset::copy_location->db_Main->prepare($sql);
358         $sth->execute(@binds);
359         
360         while ( my $rec = $sth->fetchrow_hashref ) {
361         
362                 my $cnct = new Fieldmapper::asset::copy_location;
363                 map {$cnct->$_($$rec{$_})} keys %$rec;
364                 $client->respond( $cnct );
365         }
366
367         return undef;
368 }
369 __PACKAGE__->register_method(
370         method          => 'ranged_asset_copy_location',
371         api_name        => 'open-ils.storage.ranged.asset.copy_location.retrieve',
372         argc            => 1,
373         stream          => 1,
374 );
375
376
377 sub fleshed_copy {
378         my $self = shift;
379         my $client = shift;
380         my @ids = @_;
381
382         return undef unless (@ids);
383
384         @ids = ($ids[0]) unless ($self->api_name =~ /batch/o);
385
386         for my $id ( @ids ) {
387                 next unless $id;
388                 my $cp = asset::copy->retrieve($id);
389                 next unless $cp;
390
391                 my $cp_fm = $cp->to_fieldmapper;
392                 $cp_fm->circ_lib( $cp->circ_lib->to_fieldmapper );
393                 $cp_fm->location( $cp->location->to_fieldmapper );
394                 $cp_fm->status( $cp->status->to_fieldmapper );
395                 $cp_fm->stat_cat_entries( [ map { $_->to_fieldmapper } $cp->stat_cat_entries ] );
396
397                 $client->respond( $cp_fm );
398         }
399
400         return undef;
401 }
402 __PACKAGE__->register_method(
403         api_name        => 'open-ils.storage.fleshed.asset.copy.batch.retrieve',
404         method          => 'fleshed_copy',
405         argc            => 1,
406         stream          => 1,
407 );
408 __PACKAGE__->register_method(
409         api_name        => 'open-ils.storage.fleshed.asset.copy.retrieve',
410         method          => 'fleshed_copy',
411         argc            => 1,
412 );
413
414 sub fleshed_copy_by_barcode {
415         my $self = shift;
416         my $client = shift;
417         my $bc = ''.shift;
418
419         my ($cp) = asset::copy->search( { barcode => $bc } );
420
421         return undef unless ($cp);
422
423         my $cp_fm = $cp->to_fieldmapper;
424         $cp_fm->circ_lib( $cp->circ_lib->to_fieldmapper );
425         $cp_fm->location( $cp->location->to_fieldmapper );
426         $cp_fm->status( $cp->status->to_fieldmapper );
427
428         return $cp_fm;
429 }       
430 __PACKAGE__->register_method(
431         api_name        => 'open-ils.storage.fleshed.asset.copy.search.barcode',
432         method          => 'fleshed_copy_by_barcode',
433         argc            => 1,
434         stream          => 1,
435 );
436
437
438 #XXX Fix stored proc calls
439 sub fleshed_asset_stat_cat {
440         my $self = shift;
441         my $client = shift;
442         my @list = @_;
443
444         @list = ($list[0]) unless ($self->api_name =~ /batch/o);
445         for my $sc (@list) {
446                 my $cat = asset::stat_cat->retrieve($sc);
447                 
448                 next unless ($cat);
449
450                 my $sc_fm = $cat->to_fieldmapper;
451                 $sc_fm->entries( [ map { $_->to_fieldmapper } $cat->entries ] );
452                 $client->respond( $sc_fm );
453         }
454
455         return undef;
456 }
457 __PACKAGE__->register_method(
458         api_name        => 'open-ils.storage.fleshed.asset.stat_cat.retrieve',
459         api_level       => 1,
460         method          => 'fleshed_asset_stat_cat',
461 );
462
463 __PACKAGE__->register_method(
464         api_name        => 'open-ils.storage.fleshed.asset.stat_cat.retrieve.batch',
465         api_level       => 1,
466         stream          => 1,
467         method          => 'fleshed_asset_stat_cat',
468 );
469
470
471 #XXX Fix stored proc calls
472 sub ranged_asset_stat_cat {
473         my $self = shift;
474         my $client = shift;
475         my $ou = ''.shift();
476
477         return undef unless ($ou);
478         my $s_table = asset::stat_cat->table;
479
480         my $select = <<"        SQL";
481                 SELECT  s.*
482                   FROM  $s_table s
483                         JOIN actor.org_unit_full_path(?) p ON (p.id = s.owner)
484                   ORDER BY name
485         SQL
486
487         $fleshed = 0;
488         $fleshed = 1 if ($self->api_name =~ /fleshed/o);
489
490         my $sth = asset::stat_cat->db_Main->prepare_cached($select);
491         $sth->execute($ou);
492
493         for my $sc ( map { asset::stat_cat->construct($_) } $sth->fetchall_hash ) {
494                 my $sc_fm = $sc->to_fieldmapper;
495                 $sc_fm->entries(
496                         [ $self->method_lookup( 'open-ils.storage.ranged.asset.stat_cat_entry.search.stat_cat' )->run($ou,$sc->id) ]
497                 ) if ($fleshed);
498                 $client->respond( $sc_fm );
499         }
500
501         return undef;
502 }
503 __PACKAGE__->register_method(
504         api_name        => 'open-ils.storage.ranged.fleshed.asset.stat_cat.all',
505         api_level       => 1,
506         stream          => 1,
507         method          => 'ranged_asset_stat_cat',
508 );
509
510 __PACKAGE__->register_method(
511         api_name        => 'open-ils.storage.ranged.asset.stat_cat.all',
512         api_level       => 1,
513         stream          => 1,
514         method          => 'ranged_asset_stat_cat',
515 );
516
517
518 #XXX Fix stored proc calls
519 sub multiranged_asset_stat_cat {
520         my $self = shift;
521         my $client = shift;
522         my $ous = shift;
523
524         return undef unless (defined($ous) and @$ous);
525         my $s_table = asset::stat_cat->table;
526
527         my $select = <<"        SQL";
528                 SELECT  s.*
529                   FROM  $s_table s
530                   WHERE s.owner IN ( XXX )
531                   ORDER BY name
532         SQL
533
534         my $collector = ' INTERSECT ';
535         my $entry_method = 'open-ils.storage.multiranged.intersect.asset.stat_cat_entry.search.stat_cat';
536         if ($self->api_name =~ /union/o) {
537                 $collector = ' UNION ';
538                 $entry_method = 'open-ils.storage.multiranged.union.asset.stat_cat_entry.search.stat_cat';
539         }
540
541         my $binds = join($collector, map { 'SELECT id FROM actor.org_unit_full_path(?)' } grep {defined} @$ous);
542         $select =~ s/XXX/$binds/so;
543         
544         $fleshed = 0;
545         $fleshed = 1 if ($self->api_name =~ /fleshed/o);
546
547         my $sth = asset::stat_cat->db_Main->prepare_cached($select);
548         $sth->execute(map { "$_" } grep {defined} @$ous);
549
550         for my $sc ( map { asset::stat_cat->construct($_) } $sth->fetchall_hash ) {
551                 my $sc_fm = $sc->to_fieldmapper;
552                 $sc_fm->entries(
553                         [ $self->method_lookup( $entry_method )->run($ous, $sc->id) ]
554                 ) if ($fleshed);
555                 $client->respond( $sc_fm );
556         }
557
558         return undef;
559 }
560 __PACKAGE__->register_method(
561         api_name        => 'open-ils.storage.multiranged.intersect.fleshed.asset.stat_cat.all',
562         api_level       => 1,
563         stream          => 1,
564         method          => 'multiranged_asset_stat_cat',
565 );
566 __PACKAGE__->register_method(
567         api_name        => 'open-ils.storage.multiranged.union.fleshed.asset.stat_cat.all',
568         api_level       => 1,
569         stream          => 1,
570         method          => 'multiranged_asset_stat_cat',
571 );
572
573 #XXX Fix stored proc calls
574 sub ranged_asset_stat_cat_entry {
575         my $self = shift;
576         my $client = shift;
577         my $ou = ''.shift();
578         my $sc = ''.shift();
579
580         return undef unless ($ou);
581         my $s_table = asset::stat_cat_entry->table;
582
583         my $select = <<"        SQL";
584                 SELECT  s.*
585                   FROM  $s_table s
586                         JOIN actor.org_unit_full_path(?) p ON (p.id = s.owner)
587                   WHERE stat_cat = ?
588                   ORDER BY name
589         SQL
590
591         my $sth = asset::stat_cat->db_Main->prepare_cached($select);
592         $sth->execute($ou,$sc);
593
594         for my $sce ( map { asset::stat_cat_entry->construct($_) } $sth->fetchall_hash ) {
595                 $client->respond( $sce->to_fieldmapper );
596         }
597
598         return undef;
599 }
600 __PACKAGE__->register_method(
601         api_name        => 'open-ils.storage.ranged.asset.stat_cat_entry.search.stat_cat',
602         api_level       => 1,
603         stream          => 1,
604         method          => 'ranged_asset_stat_cat_entry',
605 );
606
607 #XXX Fix stored proc calls
608 sub multiranged_asset_stat_cat_entry {
609         my $self = shift;
610         my $client = shift;
611         my $ous = shift;
612         my $sc = ''.shift();
613
614         return undef unless (defined($ous) and @$ous);
615         my $s_table = asset::stat_cat_entry->table;
616
617         my $collector = ' INTERSECT ';
618         $collector = ' UNION ' if ($self->api_name =~ /union/o);
619
620         my $select = <<"        SQL";
621                 SELECT  s.*
622                   FROM  $s_table s
623                   WHERE s.owner IN ( XXX ) and s.stat_cat = ?
624                   ORDER BY value
625         SQL
626
627         my $binds = join($collector, map { 'SELECT id FROM actor.org_unit_full_path(?)' } grep {defined} @$ous);
628         $select =~ s/XXX/$binds/so;
629         
630         my $sth = asset::stat_cat->db_Main->prepare_cached($select);
631         $sth->execute(map {"$_"} @$ous,$sc);
632
633         for my $sce ( map { asset::stat_cat_entry->construct($_) } $sth->fetchall_hash ) {
634                 $client->respond( $sce->to_fieldmapper );
635         }
636
637         return undef;
638 }
639 __PACKAGE__->register_method(
640         api_name        => 'open-ils.storage.multiranged.intersect.asset.stat_cat_entry.search.stat_cat',
641         api_level       => 1,
642         stream          => 1,
643         method          => 'multiranged_asset_stat_cat_entry',
644 );
645 __PACKAGE__->register_method(
646         api_name        => 'open-ils.storage.multiranged.union.asset.stat_cat_entry.search.stat_cat',
647         api_level       => 1,
648         stream          => 1,
649         method          => 'multiranged_asset_stat_cat_entry',
650 );
651
652
653 sub cn_ranged_tree {
654         my $self = shift;
655         my $client = shift;
656         my $cn = shift;
657         my $ou = shift;
658         my $depth = shift || 0;
659
660         my $ou_list =
661                 actor::org_unit
662                         ->db_Main
663                         ->selectcol_arrayref(
664                                 'SELECT id FROM actor.org_unit_descendants(?,?)',
665                                 {},
666                                 $ou,
667                                 $depth
668                         );
669
670         return undef unless ($ou_list and @$ou_list);
671
672         $cn = asset::call_number->retrieve( $cn );
673         return undef unless ($cn);
674
675         my $call_number = $cn->to_fieldmapper;
676         $call_number->copies([]);
677
678         $call_number->record( $cn->record->to_fieldmapper );
679         $call_number->record->fixed_fields( $cn->record->record_descriptor->next->to_fieldmapper );
680
681         for my $cp ( $cn->copies(circ_lib => $ou_list) ) {
682                 my $copy = $cp->to_fieldmapper;
683                 $copy->status( $cp->status->to_fieldmapper );
684                 $copy->location( $cp->status->to_fieldmapper );
685
686                 push @{ $call_number->copies }, $copy;
687         }
688
689         return $call_number;
690 }
691 __PACKAGE__->register_method(
692         api_name        => 'open-ils.storage.asset.call_number.ranged_tree',
693         method          => 'cn_ranged_tree',
694         argc            => 1,
695         api_level       => 1,
696 );
697
698
699 1;