View | Details | Raw Unified | Return to bug 34355
Collapse All | Expand All

(-)a/Koha/MarcOrder.pm (-149 / +405 lines)
Lines 19-24 package Koha::MarcOrder; Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
use Try::Tiny qw( catch try );
21
use Try::Tiny qw( catch try );
22
use Net::FTP;
22
23
23
use base qw(Koha::Object);
24
use base qw(Koha::Object);
24
25
Lines 41-55 use C4::ImportBatch qw( Link Here
41
    GetImportBatchRangeDesc
42
    GetImportBatchRangeDesc
42
    GetNumberOfNonZ3950ImportBatches
43
    GetNumberOfNonZ3950ImportBatches
43
);
44
);
44
use C4::Search      qw( FindDuplicate );
45
use C4::Search qw( FindDuplicate );
45
use C4::Acquisition qw( NewBasket );
46
use C4::Acquisition qw( NewBasket );
46
use C4::Biblio      qw(
47
use C4::Biblio qw(
47
    AddBiblio
48
    AddBiblio
48
    GetMarcFromKohaField
49
    GetMarcFromKohaField
49
    TransformHtmlToXml
50
    TransformHtmlToXml
50
    GetMarcQuantity
51
);
51
);
52
use C4::Items   qw( AddItemFromMarc );
52
use C4::Items qw( AddItemFromMarc );
53
use C4::Budgets qw( GetBudgetByCode );
53
use C4::Budgets qw( GetBudgetByCode );
54
54
55
use Koha::Database;
55
use Koha::Database;
Lines 70-75 Koha::MarcOrder - Koha Marc Order Object class Link Here
70
70
71
=cut
71
=cut
72
72
73
=head3 create_order_lines_from_file
74
75
    my $result = Koha::MarcOrder->create_order_lines_from_file($args);
76
77
    Controller for file staging, basket creation and order line creation when using the cronjob in marc_ordering_process.pl
78
79
=cut
80
81
sub create_order_lines_from_file {
82
    my ( $self, $args ) = @_;
83
84
    my $filename = $args->{filename};
85
    my $filepath = $args->{filepath};
86
    my $profile  = $args->{profile};
87
    my $agent    = $args->{agent};
88
89
    my $success;
90
    my $error;
91
92
    my $vendor_id = $profile->vendor_id;
93
    my $budget_id = $profile->budget_id;
94
95
    my $vendor_record = Koha::Acquisition::Booksellers->find({ id => $vendor_id });
96
97
    my $basket_id = _create_basket_for_file({
98
        filename  => $filename,
99
        vendor_id => $vendor_id
100
    });
101
102
    my $format = index($filename, '.mrc') != -1 ? 'ISO2709' : 'MARCXML';
103
    my $params = {
104
        record_type                => $profile->record_type,
105
        encoding                   => $profile->encoding,
106
        format                     => $format,
107
        filepath                   => $filepath,
108
        filename                   => $filename,
109
        comments                   => undef,
110
        parse_items                => $profile->parse_items,
111
        matcher_id                 => $profile->matcher_id,
112
        overlay_action             => $profile->overlay_action,
113
        nomatch_action             => $profile->nomatch_action,
114
        item_action                => $profile->item_action,
115
    };
116
117
    try {
118
        my $import_batch_id = _stage_file($params);
119
120
        my $import_records = Koha::Import::Records->search({
121
            import_batch_id => $import_batch_id,
122
        });
123
124
        while( my $import_record = $import_records->next ){
125
            my $result = add_biblios_from_import_record({
126
                import_batch_id => $import_batch_id,
127
                import_record   => $import_record,
128
                matcher_id      => $params->{matcher_id},
129
                overlay_action  => $params->{overlay_action},
130
                agent           => $agent,
131
            });
132
            warn "Duplicates found in $result->{duplicates_in_batch}, record was skipped." if $result->{duplicates_in_batch};
133
            next if $result->{skip};
134
135
            my $order_line_details = add_items_from_import_record({
136
                record_result   => $result->{record_result},
137
                basket_id       => $basket_id,
138
                vendor          => $vendor_record,
139
                budget_id       => $budget_id,
140
                agent           => $agent,
141
            });
142
143
            my $order_lines = create_order_lines({
144
                order_line_details => $order_line_details
145
            });
146
        };
147
        SetImportBatchStatus( $import_batch_id, 'imported' )
148
            if Koha::Import::Records->search({import_batch_id => $import_batch_id, status => 'imported' })->count
149
            == Koha::Import::Records->search({import_batch_id => $import_batch_id})->count;
150
151
        $success = 1;
152
    } catch {
153
        $success = 0;
154
        $error = $_;
155
    };
156
157
    return $success ? { success => 1, error => ''} : { success => 0, error => $error };
158
}
159
73
=head3 import_record_and_create_order_lines
160
=head3 import_record_and_create_order_lines
74
161
75
    my $result = Koha::MarcOrder->import_record_and_create_order_lines($args);
162
    my $result = Koha::MarcOrder->import_record_and_create_order_lines($args);
Lines 82-88 sub import_record_and_create_order_lines { Link Here
82
    my ( $self, $args ) = @_;
169
    my ( $self, $args ) = @_;
83
170
84
    my $import_batch_id           = $args->{import_batch_id};
171
    my $import_batch_id           = $args->{import_batch_id};
85
    my $import_record_id_selected = $args->{import_record_id_selected} || ();
172
    my @import_record_id_selected = $args->{import_record_id_selected} || ();
86
    my $matcher_id                = $args->{matcher_id};
173
    my $matcher_id                = $args->{matcher_id};
87
    my $overlay_action            = $args->{overlay_action};
174
    my $overlay_action            = $args->{overlay_action};
88
    my $import_record             = $args->{import_record};
175
    my $import_record             = $args->{import_record};
Lines 108-163 sub import_record_and_create_order_lines { Link Here
108
        skip                => $result->{skip}
195
        skip                => $result->{skip}
109
    } if $result->{skip};
196
    } if $result->{skip};
110
197
111
    my $order_line_details = add_items_from_import_record(
198
    my $order_line_details = add_items_from_import_record({
112
        {
199
        record_result      => $result->{record_result},
113
            record_result      => $result->{record_result},
200
        basket_id          => $basket_id,
114
            basket_id          => $basket_id,
201
        vendor             => $vendor,
115
            vendor             => $vendor,
202
        budget_id          => $budget_id,
116
            budget_id          => $budget_id,
203
        agent              => $agent,
117
            agent              => $agent,
204
        client_item_fields => $client_item_fields
118
            client_item_fields => $client_item_fields
205
    });
119
        }
120
    );
121
206
122
    my $order_lines = create_order_lines( { order_line_details => $order_line_details } );
207
    my $order_lines = create_order_lines({
208
        order_line_details => $order_line_details
209
    });
123
210
124
    return {
211
    return {
125
        duplicates_in_batch => 0,
212
        duplicates_in_batch => 0,
126
        skip                => 0
213
        skip                => 0
127
    };
214
    }
128
}
215
}
129
216
130
=head3 _get_MarcFieldsToOrder_syspref_data
217
=head3 _create_basket_for_file
131
218
132
    my $marc_fields_to_order = _get_MarcFieldsToOrder_syspref_data('MarcFieldsToOrder', $marcrecord, $fields);
219
    my $basket_id = _create_basket_for_file({
220
        filename  => $filename,
221
        vendor_id => $vendor_id
222
    });
133
223
134
    Fetches data from a marc record based on the mappings in the syspref MarcFieldsToOrder using the fields selected in $fields (array).
224
    Creates a basket ready to receive order lines based on the imported file
135
225
136
=cut
226
=cut
137
227
138
sub _get_MarcFieldsToOrder_syspref_data {
228
sub _create_basket_for_file {
139
    my ( $syspref_name, $record, $field_list ) = @_;
229
    my ( $args ) = @_;
140
    my $syspref = C4::Context->preference($syspref_name);
230
141
    $syspref = "$syspref\n\n";
231
    my $filename = $args->{filename};
142
    my $yaml = eval { YAML::XS::Load( Encode::encode_utf8($syspref) ); };
232
    my $vendor_id = $args->{vendor_id};
143
    if ($@) {
233
144
        warn "Unable to parse $syspref syspref : $@";
234
    # aqbasketname.basketname has a max length of 50 characters so long file names will need to be truncated
145
        return ();
235
    my $basketname = length($filename) > 50 ? substr( $filename, 0, 50 ): $filename;
146
    }
236
147
    my $r;
237
    my $basketno =
148
    for my $field_name (@$field_list) {
238
        NewBasket( $vendor_id, 0, $basketname, q{},
149
        next unless exists $yaml->{$field_name};
239
        q{} . q{} );
150
        my @fields = split /\|/, $yaml->{$field_name};
240
151
        for my $field (@fields) {
241
    return $basketno;
152
            my ( $f, $sf ) = split /\$/, $field;
242
}
153
            next unless $f and $sf;
243
154
            if ( my $v = $record->subfield( $f, $sf ) ) {
244
=head3 _stage_file
155
                $r->{$field_name} = $v;
245
246
    $file->_stage_file($params)
247
248
    Stages a file directly using parameters from a marc ordering account and without using the background job
249
    This function is a mirror of Koha::BackgroundJob::StageMARCForImport->process but with the background job functionality removed
250
251
=cut
252
253
sub _stage_file {
254
    my ( $args ) = @_;
255
256
    my $record_type                = $args->{record_type};
257
    my $encoding                   = $args->{encoding};
258
    my $format                     = $args->{format};
259
    my $filepath                   = $args->{filepath};
260
    my $filename                   = $args->{filename};
261
    my $marc_modification_template = $args->{marc_modification_template};
262
    my $comments                   = $args->{comments};
263
    my $parse_items                = $args->{parse_items};
264
    my $matcher_id                 = $args->{matcher_id};
265
    my $overlay_action             = $args->{overlay_action};
266
    my $nomatch_action             = $args->{nomatch_action};
267
    my $item_action                = $args->{item_action};
268
269
    my @messages;
270
    my ( $batch_id, $num_valid, $num_items, @import_errors );
271
    my $num_with_matches = 0;
272
    my $checked_matches  = 0;
273
    my $matcher_failed   = 0;
274
    my $matcher_code     = "";
275
276
    my $schema = Koha::Database->new->schema;
277
    try {
278
        $schema->storage->txn_begin;
279
280
        my ( $errors, $marcrecords );
281
        if ( $format eq 'MARCXML' ) {
282
            ( $errors, $marcrecords ) =
283
              C4::ImportBatch::RecordsFromMARCXMLFile( $filepath, $encoding );
284
        }
285
        elsif ( $format eq 'ISO2709' ) {
286
            ( $errors, $marcrecords ) =
287
              C4::ImportBatch::RecordsFromISO2709File( $filepath, $record_type,
288
                $encoding );
289
        }
290
        else {    # plugin based
291
            $errors = [];
292
            $marcrecords =
293
              C4::ImportBatch::RecordsFromMarcPlugin( $filepath, $format,
294
                $encoding );
295
        }
296
297
        ( $batch_id, $num_valid, $num_items, @import_errors ) = BatchStageMarcRecords(
298
            $record_type,                $encoding,
299
            $marcrecords,                $filename,
300
            $marc_modification_template, $comments,
301
            '',                          $parse_items,
302
            0
303
        );
304
305
        if ($matcher_id) {
306
            my $matcher = C4::Matcher->fetch($matcher_id);
307
            if ( defined $matcher ) {
308
                $checked_matches = 1;
309
                $matcher_code    = $matcher->code();
310
                $num_with_matches =
311
                  BatchFindDuplicates( $batch_id, $matcher, 10);
312
                SetImportBatchMatcher( $batch_id, $matcher_id );
313
                SetImportBatchOverlayAction( $batch_id, $overlay_action );
314
                SetImportBatchNoMatchAction( $batch_id, $nomatch_action );
315
                SetImportBatchItemAction( $batch_id, $item_action );
316
                $schema->storage->txn_commit;
317
            }
318
            else {
319
                $matcher_failed = 1;
320
                $schema->storage->txn_rollback;
156
            }
321
            }
157
            last if $yaml->{$field};
322
        } else {
323
            $schema->storage->txn_commit;
158
        }
324
        }
325
326
        return $batch_id;
159
    }
327
    }
160
    return $r;
328
    catch {
329
        warn $_;
330
        $schema->storage->txn_rollback;
331
        die "Something terrible has happened!"
332
          if ( $_ =~ /Rollback failed/ );    # TODO Check test: Rollback failed
333
    };
161
}
334
}
162
335
163
=head3 _get_MarcItemFieldsToOrder_syspref_data
336
=head3 _get_MarcItemFieldsToOrder_syspref_data
Lines 185-192 sub _get_MarcItemFieldsToOrder_syspref_data { Link Here
185
    }
358
    }
186
    @tags_list = List::MoreUtils::uniq(@tags_list);
359
    @tags_list = List::MoreUtils::uniq(@tags_list);
187
360
188
    my $tags_count = _verify_number_of_fields( \@tags_list, $record );
361
    die "System preference MarcItemFieldsToOrder has not been filled in. Please set the mapping values to use this cron script." if scalar(@tags_list == 0);
189
362
363
    my $tags_count = _verify_number_of_fields(\@tags_list, $record);
190
    # Return if the number of these fields in the record is not the same.
364
    # Return if the number of these fields in the record is not the same.
191
    die "Invalid number of fields detected on field $tags_count->{key}, please check this file" if $tags_count->{error};
365
    die "Invalid number of fields detected on field $tags_count->{key}, please check this file" if $tags_count->{error};
192
366
Lines 194-200 sub _get_MarcItemFieldsToOrder_syspref_data { Link Here
194
    my $fields_hash;
368
    my $fields_hash;
195
    foreach my $tag (@tags_list) {
369
    foreach my $tag (@tags_list) {
196
        my @tmp_fields;
370
        my @tmp_fields;
197
        foreach my $field ( $record->field($tag) ) {
371
        foreach my $field ($record->field($tag)) {
198
            push @tmp_fields, $field;
372
            push @tmp_fields, $field;
199
        }
373
        }
200
        $fields_hash->{$tag} = \@tmp_fields;
374
        $fields_hash->{$tag} = \@tmp_fields;
Lines 229-235 sub _get_MarcItemFieldsToOrder_syspref_data { Link Here
229
=cut
403
=cut
230
404
231
sub _verify_number_of_fields {
405
sub _verify_number_of_fields {
232
    my ( $tags_list, $record ) = @_;
406
    my ($tags_list, $record) = @_;
233
    my $tag_fields_count;
407
    my $tag_fields_count;
234
    for my $tag (@$tags_list) {
408
    for my $tag (@$tags_list) {
235
        my @fields = $record->field($tag);
409
        my @fields = $record->field($tag);
Lines 238-250 sub _verify_number_of_fields { Link Here
238
412
239
    my $tags_count;
413
    my $tags_count;
240
    foreach my $key ( keys %$tag_fields_count ) {
414
    foreach my $key ( keys %$tag_fields_count ) {
241
        if ( $tag_fields_count->{$key} > 0 ) {    # Having 0 of a field is ok
415
        if ( $tag_fields_count->{$key} > 0 ) { # Having 0 of a field is ok
242
            $tags_count //= $tag_fields_count->{$key};    # Start with the count from the first occurrence
416
            $tags_count //= $tag_fields_count->{$key}; # Start with the count from the first occurrence
243
            return { error => 1, key => $key }
417
            return { error => 1, key => $key } if $tag_fields_count->{$key} != $tags_count; # All counts of various fields should be equal if they exist
244
                if $tag_fields_count->{$key} !=
245
                $tags_count;                              # All counts of various fields should be equal if they exist
246
        }
418
        }
247
    }
419
    }
420
248
    return { error => 0, count => $tags_count };
421
    return { error => 0, count => $tags_count };
249
}
422
}
250
423
Lines 269-275 sub add_biblio_from_import_record { Link Here
269
    my ($args) = @_;
442
    my ($args) = @_;
270
443
271
    my $import_batch_id           = $args->{import_batch_id};
444
    my $import_batch_id           = $args->{import_batch_id};
272
    my $import_record_id_selected = $args->{import_record_id_selected} || ();
445
    my @import_record_id_selected = $args->{import_record_id_selected} || ();
273
    my $matcher_id                = $args->{matcher_id};
446
    my $matcher_id                = $args->{matcher_id};
274
    my $overlay_action            = $args->{overlay_action};
447
    my $overlay_action            = $args->{overlay_action};
275
    my $import_record             = $args->{import_record};
448
    my $import_record             = $args->{import_record};
Lines 277-307 sub add_biblio_from_import_record { Link Here
277
    my $duplicates_in_batch;
450
    my $duplicates_in_batch;
278
451
279
    my $duplicates_found = 0;
452
    my $duplicates_found = 0;
280
    if ( $agent eq 'client' ) {
453
    if($agent eq 'client') {
281
        return {
454
        return {
282
            record_result       => 0,
455
            record_result       => 0,
283
            duplicates_in_batch => 0,
456
            duplicates_in_batch => 0,
284
            skip                => 1
457
            skip                => 1
285
        } if not grep { $_ eq $import_record->import_record_id } @{$import_record_id_selected};
458
        } if not grep { $_ eq $import_record->import_record_id } @import_record_id_selected;
286
    }
459
    }
287
460
288
    my $marcrecord   = $import_record->get_marc_record || die "Couldn't translate marc information";
461
    my $marcrecord   = $import_record->get_marc_record || die "Couldn't translate marc information";
289
    my $matches      = $import_record->get_import_record_matches( { chosen => 1 } );
462
    my $matches      = $import_record->get_import_record_matches({ chosen => 1 });
290
    my $match        = $matches->count ? $matches->next             : undef;
463
    my $match        = $matches->count ? $matches->next : undef;
291
    my $biblionumber = $match          ? $match->candidate_match_id : 0;
464
    my $biblionumber = $match ? $match->candidate_match_id : 0;
292
465
293
    if ($biblionumber) {
466
    if ( $biblionumber ) {
294
        $import_record->status('imported')->store;
467
        $import_record->status('imported')->store;
295
        if ( $overlay_action eq 'replace' ) {
468
        if( $overlay_action eq 'replace' ){
296
            my $biblio = Koha::Biblios->find($biblionumber);
469
            my $biblio = Koha::Biblios->find( $biblionumber );
297
            $import_record->replace( { biblio => $biblio } );
470
            $import_record->replace({ biblio => $biblio });
298
        }
471
        }
299
    } else {
472
    } else {
300
        if ($matcher_id) {
473
        if ($matcher_id) {
301
            if ( $matcher_id eq '_TITLE_AUTHOR_' ) {
474
            if ( $matcher_id eq '_TITLE_AUTHOR_' ) {
302
                my @matches = FindDuplicate($marcrecord);
475
                my @matches = FindDuplicate($marcrecord);
303
                $duplicates_found = 1 if @matches;
476
                $duplicates_found = 1 if @matches;
304
            } else {
477
            }
478
            else {
305
                my $matcher = C4::Matcher->fetch($matcher_id);
479
                my $matcher = C4::Matcher->fetch($matcher_id);
306
                my @matches = $matcher->get_matches( $marcrecord, my $max_matches = 1 );
480
                my @matches = $matcher->get_matches( $marcrecord, my $max_matches = 1 );
307
                $duplicates_found = 1 if @matches;
481
                $duplicates_found = 1 if @matches;
Lines 314-320 sub add_biblio_from_import_record { Link Here
314
        }
488
        }
315
489
316
        # add the biblio if no matches were found
490
        # add the biblio if no matches were found
317
        if ( !$duplicates_found ) {
491
        if( !$duplicates_found ) {
318
            ( $biblionumber, undef ) = AddBiblio( $marcrecord, '' );
492
            ( $biblionumber, undef ) = AddBiblio( $marcrecord, '' );
319
            $import_record->status('imported')->store;
493
            $import_record->status('imported')->store;
320
        }
494
        }
Lines 352-358 sub add_biblio_from_import_record { Link Here
352
=cut
526
=cut
353
527
354
sub add_items_from_import_record {
528
sub add_items_from_import_record {
355
    my ($args) = @_;
529
    my ( $args ) = @_;
356
530
357
    my $record_result      = $args->{record_result};
531
    my $record_result      = $args->{record_result};
358
    my $basket_id          = $args->{basket_id};
532
    my $basket_id          = $args->{basket_id};
Lines 372-400 sub add_items_from_import_record { Link Here
372
546
373
        my $marc_item_fields_to_order = _get_MarcItemFieldsToOrder_syspref_data($marcrecord);
547
        my $marc_item_fields_to_order = _get_MarcItemFieldsToOrder_syspref_data($marcrecord);
374
548
375
        my $item_fields = {
549
        my $item_fields = _create_item_fields_from_syspref(
376
            homebranch       => $marc_item_fields_to_order->{homebranch},
550
            {
377
            holdingbranch    => $marc_item_fields_to_order->{holdingbranch},
551
                marc_fields_to_order      => $marc_fields_to_order,
378
            itype            => $marc_item_fields_to_order->{itype},
552
                marc_item_fields_to_order => $marc_item_fields_to_order,
379
            nonpublic_note   => $marc_item_fields_to_order->{nonpublic_note},
553
                budget_id                 => $budget_id
380
            public_note      => $marc_item_fields_to_order->{public_note},
554
            }
381
            loc              => $marc_item_fields_to_order->{loc},
555
        );
382
            ccode            => $marc_item_fields_to_order->{ccode},
383
            notforloan       => $marc_item_fields_to_order->{notforloan},
384
            uri              => $marc_item_fields_to_order->{uri},
385
            copyno           => $marc_item_fields_to_order->{copyno},
386
            quantity         => $marc_item_fields_to_order->{quantity},
387
            price            => $marc_item_fields_to_order->{price},
388
            replacementprice => $marc_item_fields_to_order->{replacementprice},
389
            itemcallnumber   => $marc_item_fields_to_order->{itemcallnumber},
390
            budget_code      => $marc_item_fields_to_order->{budget_code},
391
            c_quantity       => $marc_fields_to_order->{quantity},
392
            c_budget_code    => $marc_fields_to_order->{budget_code},
393
            c_price          => $marc_fields_to_order->{price},
394
            c_discount       => $marc_fields_to_order->{discount},
395
            c_sort1          => $marc_fields_to_order->{sort1},
396
            c_sort2          => $marc_fields_to_order->{sort2},
397
        };
398
556
399
        my $order_line_fields = parse_input_into_order_line_fields(
557
        my $order_line_fields = parse_input_into_order_line_fields(
400
            {
558
            {
Lines 455-473 sub add_items_from_import_record { Link Here
455
=cut
613
=cut
456
614
457
sub create_order_lines {
615
sub create_order_lines {
458
    my ($args) = @_;
616
    my ( $args ) = @_;
459
617
460
    my $order_line_details = $args->{order_line_details};
618
    my $order_line_details = $args->{order_line_details};
461
619
462
    foreach my $order_detail ( @{$order_line_details} ) {
620
    foreach  my $order_detail ( @{ $order_line_details } ) {
463
        my @itemnumbers = $order_detail->{itemnumbers} || ();
621
        my @itemnumbers = $order_detail->{itemnumbers};
464
        delete( $order_detail->{itemnumbers} );
622
        delete($order_detail->{itemnumber});
465
        my $order = Koha::Acquisition::Order->new( \%{$order_detail} );
623
        my $order = Koha::Acquisition::Order->new( \%{ $order_detail } );
466
        $order->populate_with_prices_for_ordering();
624
        $order->populate_with_prices_for_ordering();
467
        $order->populate_with_prices_for_receiving();
625
        $order->populate_with_prices_for_receiving();
468
        $order->store;
626
        $order->store;
469
        foreach my $itemnumber (@itemnumbers) {
627
        foreach my $itemnumber ( @itemnumbers ) {
470
            $order->add_item($itemnumber);
628
            $order->add_item( $itemnumber );
471
        }
629
        }
472
    }
630
    }
473
    return;
631
    return;
Lines 737-743 my $order_line_fields = parse_input_into_order_line_fields( Link Here
737
    }
895
    }
738
);
896
);
739
897
740
741
=cut
898
=cut
742
899
743
sub parse_input_into_order_line_fields {
900
sub parse_input_into_order_line_fields {
Lines 751-820 sub parse_input_into_order_line_fields { Link Here
751
    my $fields       = $args->{fields};
908
    my $fields       = $args->{fields};
752
909
753
    my $quantity        = $fields->{quantity} || 1;
910
    my $quantity        = $fields->{quantity} || 1;
754
    my @homebranches    = $client ? @{ $fields->{homebranches} }    : ( ( $fields->{homebranch} ) x $quantity );
911
    # my @homebranches    = $client ? @{ $fields->{homebranches} }    : ( ( $fields->{homebranch} ) x $quantity );
755
    my @holdingbranches = $client ? @{ $fields->{holdingbranches} } : ( ( $fields->{holdingbranch} ) x $quantity );
912
    # my @holdingbranches = $client ? @{ $fields->{holdingbranches} } : ( ( $fields->{holdingbranch} ) x $quantity );
756
    my @itypes          = $client ? @{ $fields->{itypes} }          : ( ( $fields->{itype} ) x $quantity );
913
    # my @itypes          = $client ? @{ $fields->{itypes} }          : ( ( $fields->{itype} ) x $quantity );
757
    my @nonpublic_notes = $client ? @{ $fields->{nonpublic_notes} } : ( ( $fields->{nonpublic_note} ) x $quantity );
914
    # my @nonpublic_notes = $client ? @{ $fields->{nonpublic_notes} } : ( ( $fields->{nonpublic_note} ) x $quantity );
758
    my @public_notes    = $client ? @{ $fields->{public_notes} }    : ( ( $fields->{public_note} ) x $quantity );
915
    # my @public_notes    = $client ? @{ $fields->{public_notes} }    : ( ( $fields->{public_note} ) x $quantity );
759
    my @locs            = $client ? @{ $fields->{locs} }            : ( ( $fields->{loc} ) x $quantity );
916
    # my @locs            = $client ? @{ $fields->{locs} }            : ( ( $fields->{loc} ) x $quantity );
760
    my @ccodes          = $client ? @{ $fields->{ccodes} }          : ( ( $fields->{ccode} ) x $quantity );
917
    # my @ccodes          = $client ? @{ $fields->{ccodes} }          : ( ( $fields->{ccode} ) x $quantity );
761
    my @notforloans     = $client ? @{ $fields->{notforloans} }     : ( ( $fields->{notforloan} ) x $quantity );
918
    # my @notforloans     = $client ? @{ $fields->{notforloans} }     : ( ( $fields->{notforloan} ) x $quantity );
762
    my @uris            = $client ? @{ $fields->{uris} }            : ( ( $fields->{uri} ) x $quantity );
919
    # my @uris            = $client ? @{ $fields->{uris} }            : ( ( $fields->{uri} ) x $quantity );
763
    my @copynos         = $client ? @{ $fields->{copynos} }         : ( ( $fields->{copyno} ) x $quantity );
920
    # my @copynos         = $client ? @{ $fields->{copynos} }         : ( ( $fields->{copyno} ) x $quantity );
764
    my @itemprices      = $client ? @{ $fields->{itemprices} }      : ( ( $fields->{price} ) x $quantity );
921
    # my @itemprices      = $client ? @{ $fields->{itemprices} }      : ( ( $fields->{price} ) x $quantity );
765
    my @replacementprices =
922
    # my @replacementprices =
766
        $client ? @{ $fields->{replacementprices} } : ( ( $fields->{replacementprice} ) x $quantity );
923
    #     $client ? @{ $fields->{replacementprices} } : ( ( $fields->{replacementprice} ) x $quantity );
767
    my @itemcallnumbers     = $client ? @{ $fields->{itemcallnumbers} } : ( ( $fields->{itemcallnumber} ) x $quantity );
924
    # my @itemcallnumbers     = $client ? @{ $fields->{itemcallnumbers} } : ( ( $fields->{itemcallnumber} ) x $quantity );
768
    my $c_quantity          = $client ? $fields->{c_quantity}           : $fields->{c_quantity};
925
    # my $c_quantity          = $client ? $fields->{c_quantity}           : $fields->{c_quantity};
769
    my $c_budget_id         = $client ? $fields->{c_budget_id}          : $fields->{c_budget_id};
926
    # my $c_budget_id         = $client ? $fields->{c_budget_id}          : $fields->{c_budget_id};
770
    my $c_discount          = $client ? $fields->{c_discount}           : $fields->{c_discount};
927
    # my $c_discount          = $client ? $fields->{c_discount}           : $fields->{c_discount};
771
    my $c_sort1             = $client ? $fields->{c_sort1}              : $fields->{c_sort1};
928
    # my $c_sort1             = $client ? $fields->{c_sort1}              : $fields->{c_sort1};
772
    my $c_sort2             = $client ? $fields->{c_sort2}              : $fields->{c_sort2};
929
    # my $c_sort2             = $client ? $fields->{c_sort2}              : $fields->{c_sort2};
773
    my $c_replacement_price = $client ? $fields->{c_replacement_price}  : $fields->{c_replacement_price};
930
    # my $c_replacement_price = $client ? $fields->{c_replacement_price}  : $fields->{c_replacement_price};
774
    my $c_price             = $client ? $fields->{c_price}              : $fields->{c_price};
931
    # my $c_price             = $client ? $fields->{c_price}              : $fields->{c_price};
775
932
776
    # If using the cronjob, we want to default to the account budget if not mapped on the record
933
    # If using the cronjob, we want to default to the account budget if not mapped on the record
777
    my $item_budget_id;
934
    # my $item_budget_id;
778
    if ( !$client && ( $fields->{budget_code} || $fields->{c_budget_code} ) ) {
935
    # if ( !$client && ( $fields->{budget_code} || $fields->{c_budget_code} ) ) {
779
        my $budget_code = $fields->{budget_code} || $fields->{c_budget_code};
936
    #     my $budget_code = $fields->{budget_code} || $fields->{c_budget_code};
780
        my $item_budget = GetBudgetByCode($budget_code);
937
    #     my $item_budget = GetBudgetByCode($budget_code);
781
        if ($item_budget) {
938
    #     if ($item_budget) {
782
            $item_budget_id = $item_budget->{budget_id};
939
    #         $item_budget_id = $item_budget->{budget_id};
783
        } else {
940
    #     } else {
784
            $item_budget_id = $budget_id;
941
    #         $item_budget_id = $budget_id;
785
        }
942
    #     }
786
    } else {
943
    # } else {
787
        $item_budget_id = $budget_id;
944
    #     $item_budget_id = $budget_id;
788
    }
945
    # }
789
    my @budget_codes = $client ? @{ $fields->{budget_codes} } : ($item_budget_id);
946
    # my @budget_codes = $client ? @{ $fields->{budget_codes} } : ($item_budget_id);
790
    my $loop_limit   = $client ? scalar(@homebranches)        : $quantity;
947
    # my $loop_limit   = $client ? scalar(@homebranches)        : $quantity;
791
948
792
    my $order_line_fields = {
949
    my $order_line_fields = {
793
        biblionumber        => $biblionumber,
950
        biblionumber        => $biblionumber,
794
        homebranch          => \@homebranches,
951
        homebranch          => $fields->{homebranches},
795
        holdingbranch       => \@holdingbranches,
952
        holdingbranch       => $fields->{holdingbranches},
796
        itemnotes_nonpublic => \@nonpublic_notes,
953
        itemnotes_nonpublic => $fields->{nonpublic_notes},
797
        itemnotes           => \@public_notes,
954
        itemnotes           => $fields->{public_notes},
798
        location            => \@locs,
955
        location            => $fields->{locs},
799
        ccode               => \@ccodes,
956
        ccode               => $fields->{ccodes},
800
        itype               => \@itypes,
957
        itype               => $fields->{itypes},
801
        notforloan          => \@notforloans,
958
        notforloan          => $fields->{notforloans},
802
        uri                 => \@uris,
959
        uri                 => $fields->{uris},
803
        copynumber          => \@copynos,
960
        copynumber          => $fields->{copynos},
804
        price               => \@itemprices,
961
        price               => $fields->{itemprices},
805
        replacementprice    => \@replacementprices,
962
        replacementprice    => $fields->{replacementprices},
806
        itemcallnumber      => \@itemcallnumbers,
963
        itemcallnumber      => $fields->{itemcallnumbers},
807
        budget_code         => \@budget_codes,
964
        budget_code         => $fields->{budget_codes},
808
        loop_limit          => $loop_limit,
965
        loop_limit          => $quantity,
809
        basket_id           => $basket_id,
966
        basket_id           => $basket_id,
810
        budget_id           => $budget_id,
967
        budget_id           => $budget_id,
811
        c_quantity          => $c_quantity,
968
        c_quantity          => $fields->{c_quantity},
812
        c_budget_id         => $c_budget_id,
969
        c_budget_id         => $fields->{c_budget_id},
813
        c_discount          => $c_discount,
970
        c_discount          => $fields->{c_discount},
814
        c_sort1             => $c_sort1,
971
        c_sort1             => $fields->{c_sort1},
815
        c_sort2             => $c_sort2,
972
        c_sort2             => $fields->{c_sort2},
816
        c_replacement_price => $c_replacement_price,
973
        c_replacement_price => $fields->{c_replacement_price},
817
        c_price             => $c_price,
974
        c_price             => $fields->{c_price},
818
    };
975
    };
819
976
820
    return $order_line_fields;
977
    return $order_line_fields;
Lines 901-904 sub create_items_and_generate_order_hash { Link Here
901
    return \@order_line_details;
1058
    return \@order_line_details;
902
}
1059
}
903
1060
1061
=head3 _create_item_fields_from_syspref
1062
1063
Takes the two sysprefs and returns the item fields required to process and create orderlines
1064
1065
my $item_fields = _create_item_fields_from_syspref(
1066
    {
1067
        marc_fields_to_order      => $marc_fields_to_order,
1068
        marc_item_fields_to_order => $marc_item_fields_to_order
1069
    }
1070
);
1071
1072
=cut
1073
1074
sub _create_item_fields_from_syspref {
1075
    my ($args) = @_;
1076
1077
    my $marc_item_fields_to_order = $args->{marc_item_fields_to_order};
1078
    my $marc_fields_to_order      = $args->{marc_fields_to_order};
1079
    my $budget_id                 = $args->{budget_id};
1080
1081
    my @homebranches      = ();
1082
    my @holdingbranches   = ();
1083
    my @itypes            = ();
1084
    my @nonpublic_notes   = ();
1085
    my @public_notes      = ();
1086
    my @locs              = ();
1087
    my @ccodes            = ();
1088
    my @notforloans       = ();
1089
    my @uris              = ();
1090
    my @copynos           = ();
1091
    my @budget_codes      = ();
1092
    my @itemprices        = ();
1093
    my @replacementprices = ();
1094
    my @itemcallnumbers   = ();
1095
1096
    foreach my $infoset (@$marc_item_fields_to_order) {
1097
        my $quantity = $infoset->{quantity} || 1;
1098
        for ( my $i = 0 ; $i < $quantity ; $i++ ) {
1099
            my $budget_code;
1100
            if(!$infoset->{budget_code}) {
1101
                if($marc_fields_to_order->{budget_code}) {
1102
                    $budget_code = $marc_fields_to_order->{budget_code};  
1103
                }
1104
            } else {
1105
                $budget_code = $infoset->{budget_code};
1106
            }
1107
1108
            my $item_budget_id;
1109
            my $item_budget = GetBudgetByCode($budget_code);
1110
            if ($item_budget) {
1111
                $item_budget_id = $item_budget->{budget_id};
1112
            } else {
1113
                $item_budget_id = $budget_id;
1114
            }
1115
1116
            push @homebranches,      $infoset->{homebranch};
1117
            push @holdingbranches,   $infoset->{holdingbranch};
1118
            push @itypes,            $infoset->{itype};
1119
            push @nonpublic_notes,   $infoset->{nonpublic_note};
1120
            push @public_notes,      $infoset->{public_note};
1121
            push @locs,              $infoset->{loc};
1122
            push @ccodes,            $infoset->{ccode};
1123
            push @notforloans,       $infoset->{notforloan};
1124
            push @uris,              $infoset->{uri};
1125
            push @copynos,           $infoset->{copyno};
1126
            push @budget_codes,      $item_budget_id;
1127
            push @itemprices,        $infoset->{itemprice};
1128
            push @replacementprices, $infoset->{replacementprice};
1129
            push @itemcallnumbers,   $infoset->{itemcallnumber};
1130
        }
1131
    }
1132
1133
    my $item_fields = {
1134
        quantity          => scalar(@homebranches),
1135
        homebranches      => \@homebranches,
1136
        holdingbranches   => \@holdingbranches,
1137
        itypes            => \@itypes,
1138
        nonpublic_notes   => \@nonpublic_notes,
1139
        public_notes      => \@public_notes,
1140
        locs              => \@locs,
1141
        ccodes            => \@ccodes,
1142
        notforloans       => \@notforloans,
1143
        uris              => \@uris,
1144
        copynos           => \@copynos,
1145
        budget_codes      => \@budget_codes,
1146
        itemprices        => \@itemprices,
1147
        replacementprices => \@replacementprices,
1148
        itemcallnumbers   => \@itemcallnumbers,
1149
        c_quantity        => $marc_fields_to_order->{quantity},
1150
        c_budget_code     => $marc_fields_to_order->{budget_code},
1151
        c_price           => $marc_fields_to_order->{price},
1152
        c_discount        => $marc_fields_to_order->{discount},
1153
        c_sort1           => $marc_fields_to_order->{sort1},
1154
        c_sort2           => $marc_fields_to_order->{sort2},
1155
    };
1156
1157
    return $item_fields;
1158
}
1159
904
1;
1160
1;
(-)a/misc/cronjobs/marc_ordering_process.pl (-1 / +128 lines)
Line 0 Link Here
0
- 
1
2
#!/usr/bin/perl
3
4
# This file is part of Koha.
5
#
6
# Copyright (C) 2023 PTFS Europe Ltd
7
#
8
# Koha is free software; you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# Koha is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21
=head1 NAME
22
23
marc_ordering_process.pl - cron script to retrieve marc files and create order lines
24
25
=head1 SYNOPSIS
26
27
./marc_ordering_process.pl [-c|--confirm] [-v|--verbose]
28
29
or, in crontab:
30
# Once every day
31
0 3 * * * marc_ordering_process.pl -c
32
33
=head1 DESCRIPTION
34
35
This script searches for new marc files in an SFTP location
36
If there are new files, it stages those files, adds bilbios/items and creates order lines
37
38
=head1 OPTIONS
39
40
=over
41
42
=item B<-v|--verbose>
43
44
Print report to standard out.
45
46
=item B<-c|--confirm>
47
48
Without this parameter no changes will be made
49
50
=back
51
52
=cut
53
54
use Modern::Perl;
55
use Pod::Usage qw( pod2usage );
56
use Getopt::Long qw( GetOptions );
57
use File::Copy qw( copy move );
58
59
use Koha::Script -cron;
60
use Koha::MarcOrder;
61
use Koha::MarcOrderAccounts;
62
63
use C4::Log qw( cronlogaction );
64
65
my $command_line_options = join(" ",@ARGV);
66
67
my ( $help, $verbose, $confirm );
68
GetOptions(
69
    'h|help' => \$help,
70
    'v|verbose'    => \$verbose,
71
    'c|confirm'     => \$confirm,
72
) || pod2usage(1);
73
74
pod2usage(0) if $help;
75
76
cronlogaction({ info => $command_line_options });
77
78
$verbose = 1 unless $verbose or $confirm;
79
print "Test run only\n" unless $confirm;
80
81
print "Fetching marc ordering accounts\n" if $verbose;
82
my @accounts = Koha::MarcOrderAccounts->search(
83
    {},
84
    {
85
        join => ['vendor', 'budget']
86
    }
87
)->as_list;
88
89
if(scalar(@accounts) == 0) {
90
    print "No accounts found - you must create a Marc order account for this cronjob to run\n" if $verbose;
91
}
92
93
foreach my $acct ( @accounts ) {
94
    if($verbose) {
95
        say sprintf "Starting marc ordering process for %s", $acct->vendor->name;
96
        say sprintf "Looking for new files in %s", $acct->download_directory;
97
    }
98
99
    my $working_dir = $acct->download_directory;
100
    opendir my $dir, $working_dir or die "Can't open filepath";
101
    my @files = grep { /\.(mrc|marcxml|mrk)/i } readdir $dir;
102
    closedir $dir;
103
104
    foreach my $filename ( @files ) {
105
        say sprintf "Creating order lines from file %s", $filename if $verbose;
106
        if($confirm) {
107
            my $full_path = "$working_dir/$filename";
108
            my $args = {
109
                filename => $filename,
110
                filepath => $full_path,
111
                profile  => $acct,
112
                agent    => 'cron'
113
            };
114
            my $result = Koha::MarcOrder->create_order_lines_from_file($args);
115
            if($result->{success}) {
116
                say sprintf "Successfully processed file: %s", $filename if $verbose;
117
                unlink $full_path;
118
            } else {
119
                say sprintf "Error processing file: %s", $filename if $verbose;
120
                say sprintf "Error message: %s", $result->{error} if $verbose;
121
            };
122
        }
123
    }
124
    print "All files completed\n";
125
    print "Moving to next account\n\n";
126
}
127
print "Process complete\n";
128
cronlogaction({ action => 'End', info => "COMPLETED" });

Return to bug 34355