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

(-)a/C4/Suggestions.pm (+42 lines)
Lines 27-32 use C4::Context; Link Here
27
use C4::Output;
27
use C4::Output;
28
use C4::Debug;
28
use C4::Debug;
29
use C4::Letters;
29
use C4::Letters;
30
use C4::Biblio qw( GetMarcFromKohaField );
30
use Koha::DateUtils;
31
use Koha::DateUtils;
31
use Koha::Suggestions;
32
use Koha::Suggestions;
32
33
Lines 48-53 our @EXPORT = qw( Link Here
48
  SearchSuggestion
49
  SearchSuggestion
49
  DelSuggestionsOlderThan
50
  DelSuggestionsOlderThan
50
  GetUnprocessedSuggestions
51
  GetUnprocessedSuggestions
52
  MarcRecordFromNewSuggestion
51
);
53
);
52
54
53
=head1 NAME
55
=head1 NAME
Lines 653-658 sub GetUnprocessedSuggestions { Link Here
653
    return $s;
655
    return $s;
654
}
656
}
655
657
658
=head2 MarcRecordFromNewSuggestion
659
660
    $record = MarcRecordFromNewSuggestion ( $suggestion )
661
662
This function build a marc record object from a suggestion
663
664
=cut
665
666
sub MarcRecordFromNewSuggestion {
667
    my ($suggestion) = @_;
668
    my $record = MARC::Record->new();
669
670
    my ($title_tag, $title_subfield) = GetMarcFromKohaField('biblio.title', '');
671
    $record->append_fields(
672
        MARC::Field->new($title_tag, ' ', ' ', $title_subfield => $suggestion->{title})
673
    );
674
675
    my ($author_tag, $author_subfield) = GetMarcFromKohaField('biblio.author', '');
676
    if ($record->field( $author_tag )) {
677
        $record->field( $author_tag )->add_subfields( $author_subfield => $suggestion->{author} );
678
    }
679
    else {
680
        $record->append_fields(
681
            MARC::Field->new($author_tag, ' ', ' ', $author_subfield => $suggestion->{author})
682
        );
683
    }
684
685
    my ($it_tag, $it_subfield) = GetMarcFromKohaField('biblioitems.itemtype', '');
686
    if ($record->field( $it_tag )) {
687
        $record->field( $it_tag )->add_subfields( $it_subfield => $suggestion->{itemtype} );
688
    }
689
    else {
690
        $record->append_fields(
691
            MARC::Field->new($it_tag, ' ', ' ', $it_subfield => $suggestion->{author})
692
        );
693
    }
694
695
    return $record;
696
}
697
656
1;
698
1;
657
__END__
699
__END__
658
700
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-suggestions.tt (-15 / +32 lines)
Lines 40-118 Link Here
40
                            <p>Please fill out this form to make a purchase suggestion. You will receive an email when the library processes your suggestion.</p>
40
                            <p>Please fill out this form to make a purchase suggestion. You will receive an email when the library processes your suggestion.</p>
41
                            <p>Only certain fields (marked in red) are required, but the more information you enter the easier it will be for the librarians to find the title you're requesting. The "Notes" field can be used to provide any additional information.</p>
41
                            <p>Only certain fields (marked in red) are required, but the more information you enter the easier it will be for the librarians to find the title you're requesting. The "Notes" field can be used to provide any additional information.</p>
42
42
43
                            [% FOR m IN messages %]
44
                                <div class="alert alert-[% m.type %]">
45
                                    [% SWITCH m.code %]
46
                                    [% CASE 'biblio_exists' %]
47
                                        A similar document already exists: <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% m.id %]">[% m.title %]</a>. Click on "Confirm your suggestion" to ignore this message.
48
                                    [% CASE %]
49
                                        [% m.code %]
50
                                    [% END %]
51
                                </div>
52
                            [% END %]
53
43
                            <form action="/cgi-bin/koha/opac-suggestions.pl" method="post" id="add_suggestion_form">
54
                            <form action="/cgi-bin/koha/opac-suggestions.pl" method="post" id="add_suggestion_form">
44
                                <fieldset class="rows">
55
                                <fieldset class="rows">
45
                                    <ol>
56
                                    <ol>
46
                                        <li>
57
                                        <li>
47
                                            [% IF ( title_required ) %]
58
                                            [% IF ( title_required ) %]
48
                                                <label for="title" class="required">Title:</label>
59
                                                <label for="title" class="required">Title:</label>
49
                                                <input type="text" id="title" name="title" class="span6" maxlength="255" required="required" />
60
                                                <input type="text" id="title" name="title" class="span6" maxlength="255" value="[% title %]" required="required" />
50
                                                <span class="required">Required</span>
61
                                                <span class="required">Required</span>
51
                                            [% ELSE %]
62
                                            [% ELSE %]
52
                                                <label for="title">Title:</label>
63
                                                <label for="title">Title:</label>
53
                                                <input type="text" id="title" name="title" class="span6" maxlength="255" />
64
                                                <input type="text" id="title" name="title" class="span6" maxlength="255" value="[% title %]" />
54
                                            [% END %]
65
                                            [% END %]
55
                                        </li>
66
                                        </li>
56
                                        <li>
67
                                        <li>
57
                                            [% IF ( author_required ) %]
68
                                            [% IF ( author_required ) %]
58
                                                <label for="author" class="required">Author:</label>
69
                                                <label for="author" class="required">Author:</label>
59
                                                <input type="text" id="author" name="author" class="span6" maxlength="80" required="required" />
70
                                                <input type="text" id="author" name="author" class="span6" maxlength="80" value="[% author %]" required="required" />
60
                                                <span class="required">Required</span>
71
                                                <span class="required">Required</span>
61
                                            [% ELSE %]
72
                                            [% ELSE %]
62
                                                <label for="author">Author:</label>
73
                                                <label for="author">Author:</label>
63
                                                <input type="text" id="author" name="author" class="span6" maxlength="80" />
74
                                                <input type="text" id="author" name="author" class="span6" maxlength="80" value="[% author %]" />
64
                                            [% END %]
75
                                            [% END %]
65
                                        </li>
76
                                        </li>
66
                                        <li>
77
                                        <li>
67
                                            <div title="Copyright or publication year, for example: 2016">
78
                                            <div title="Copyright or publication year, for example: 2016">
68
                                                [% IF ( copyrightdate_required ) %]
79
                                                [% IF ( copyrightdate_required ) %]
69
                                                    <label for="copyrightdate" class="required">Copyright date:</label>
80
                                                    <label for="copyrightdate" class="required">Copyright date:</label>
70
                                                    <input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" required="required" />
81
                                                    <input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" value="[% copyrightdate %]" required="required" />
71
                                                <span class="required">Required</span>
82
                                                <span class="required">Required</span>
72
                                                [% ELSE %]
83
                                                [% ELSE %]
73
                                                    <label for="copyrightdate">Copyright date:</label>
84
                                                    <label for="copyrightdate">Copyright date:</label>
74
                                                    <input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" />
85
                                                    <input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" value="[% copyrightdate %]" />
75
                                                [% END %]
86
                                                [% END %]
76
                                            </div>
87
                                            </div>
77
                                        </li>
88
                                        </li>
78
                                        <li>
89
                                        <li>
79
                                            [% IF ( isbn_required ) %]
90
                                            [% IF ( isbn_required ) %]
80
                                                <label for="isbn" class="required">Standard number (ISBN, ISSN or other):</label>
91
                                                <label for="isbn" class="required">Standard number (ISBN, ISSN or other):</label>
81
                                                <input type="text" id="isbn" name="isbn"  maxlength="80" required="required" />
92
                                                <input type="text" id="isbn" name="isbn"  maxlength="80" value="[% isbn %]" required="required" />
82
                                                <span class="required">Required</span>
93
                                                <span class="required">Required</span>
83
                                            [% ELSE %]
94
                                            [% ELSE %]
84
                                                <label for="isbn">Standard number (ISBN, ISSN or other):</label>
95
                                                <label for="isbn">Standard number (ISBN, ISSN or other):</label>
85
                                                <input type="text" id="isbn" name="isbn"  maxlength="80" />
96
                                                <input type="text" id="isbn" name="isbn"  maxlength="80" value="[% isbn %]" />
86
                                            [% END %]
97
                                            [% END %]
87
                                        </li>
98
                                        </li>
88
                                        <li>
99
                                        <li>
89
                                            [% IF ( publishercode_required ) %]
100
                                            [% IF ( publishercode_required ) %]
90
                                                <label for="publishercode" class="required">Publisher:</label>
101
                                                <label for="publishercode" class="required">Publisher:</label>
91
                                                <input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" required="required" />
102
                                                <input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" value="[% publishercode %]" required="required" />
92
                                                <span class="required">Required</span>
103
                                                <span class="required">Required</span>
93
                                            [% ELSE %]
104
                                            [% ELSE %]
94
                                                <label for="publishercode">Publisher:</label>
105
                                                <label for="publishercode">Publisher:</label>
95
                                                <input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" />
106
                                                <input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" value="[% publishercode %]" />
96
                                            [% END %]
107
                                            [% END %]
97
                                        </li>
108
                                        </li>
98
                                        <li>
109
                                        <li>
99
                                            [% IF ( collectiontitle_required ) %]
110
                                            [% IF ( collectiontitle_required ) %]
100
                                                <label for="collectiontitle" class="required">Collection title:</label>
111
                                                <label for="collectiontitle" class="required">Collection title:</label>
101
                                                <input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" required="required" />
112
                                                <input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" value="[% collectiontitle %]" required="required" />
102
                                                <span class="required">Required</span>
113
                                                <span class="required">Required</span>
103
                                            [% ELSE %]
114
                                            [% ELSE %]
104
                                                <label for="collectiontitle">Collection title:</label>
115
                                                <label for="collectiontitle">Collection title:</label>
105
                                                <input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" />
116
                                                <input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" value="[% collectiontitle %]" />
106
                                            [% END %]
117
                                            [% END %]
107
                                        </li>
118
                                        </li>
108
                                        <li>
119
                                        <li>
109
                                            [% IF ( place_required ) %]
120
                                            [% IF ( place_required ) %]
110
                                                <label for="place" class="required">Publication place:</label>
121
                                                <label for="place" class="required">Publication place:</label>
111
                                                <input type="text" id="place" name="place" required="required" maxlength="80" />
122
                                                <input type="text" id="place" name="place" required="required" maxlength="80" value="[% place %]" />
112
                                                <span class="required">Required</span>
123
                                                <span class="required">Required</span>
113
                                            [% ELSE %]
124
                                            [% ELSE %]
114
                                                <label for="place">Publication place:</label>
125
                                                <label for="place">Publication place:</label>
115
                                                <input type="text" id="place" name="place"  maxlength="80" />
126
                                                <input type="text" id="place" name="place"  maxlength="80" value="[% place %]" />
116
                                            [% END %]
127
                                            [% END %]
117
                                        </li>
128
                                        </li>
118
                                        <li id="opac-suggestion-quantity">
129
                                        <li id="opac-suggestion-quantity">
Lines 181-186 Link Here
181
                                            [% ELSE %]
192
                                            [% ELSE %]
182
                                                <label for="note">Notes:</label>
193
                                                <label for="note">Notes:</label>
183
                                                <textarea name="note" id="note" rows="5" cols="40"></textarea>
194
                                                <textarea name="note" id="note" rows="5" cols="40"></textarea>
195
                                                <textarea name="note" id="note" rows="5" cols="40">[% note %]</textarea>
184
                                            [% END %]
196
                                            [% END %]
185
                                        </li>
197
                                        </li>
186
198
Lines 194-200 Link Here
194
                                <fieldset class="action">
206
                                <fieldset class="action">
195
                                    <input type="hidden" name="suggested_by_anyone" value="[% suggested_by_anyone | html %]" />
207
                                    <input type="hidden" name="suggested_by_anyone" value="[% suggested_by_anyone | html %]" />
196
                                    <input type="hidden" name="op" value="add_confirm" />
208
                                    <input type="hidden" name="op" value="add_confirm" />
197
                                    <input type="submit" class="btn" value="Submit your suggestion" /> <a class="action" href="/cgi-bin/koha/opac-suggestions.pl">Cancel</a>
209
                                    [% IF ( need_confirm ) %]
210
                                        <input type="submit" onclick="this.form.op.value = 'add_confirm'; this.form.submit();" class="btn" value="Confirm your suggestion" />
211
                                    [% ELSE %]
212
                                        <input type="submit" class="btn" value="Submit your suggestion" />
213
                                    [% END %]
214
                                    <a class="action" href="/cgi-bin/koha/opac-suggestions.pl">Cancel</a>
198
                                </fieldset>
215
                                </fieldset>
199
                            </form>
216
                            </form>
200
                            [% END %]
217
                            [% END %]
(-)a/opac/opac-suggestions.pl (-1 / +15 lines)
Lines 27-32 use C4::Output; Link Here
27
use C4::Suggestions;
27
use C4::Suggestions;
28
use C4::Koha;
28
use C4::Koha;
29
use C4::Scrubber;
29
use C4::Scrubber;
30
use C4::Search qw( FindDuplicate );
30
31
31
use Koha::AuthorisedValues;
32
use Koha::AuthorisedValues;
32
use Koha::Libraries;
33
use Koha::Libraries;
Lines 39-44 my $op = $input->param('op'); Link Here
39
my $suggestion      = $input->Vars;
40
my $suggestion      = $input->Vars;
40
my $negcaptcha      = $input->param('negcap');
41
my $negcaptcha      = $input->param('negcap');
41
my $suggested_by_anyone = $input->param('suggested_by_anyone') || 0;
42
my $suggested_by_anyone = $input->param('suggested_by_anyone') || 0;
43
my $need_confirm    = 0;
42
44
43
# If a spambot accidentally populates the 'negcap' field in the sugesstions form, then silently skip and return.
45
# If a spambot accidentally populates the 'negcap' field in the sugesstions form, then silently skip and return.
44
if ($negcaptcha ) {
46
if ($negcaptcha ) {
Lines 56-62 if ( ! C4::Context->preference('suggestion') ) { Link Here
56
    exit;
58
    exit;
57
}
59
}
58
60
59
delete $suggestion->{$_} foreach qw<op suggested_by_anyone>;
61
delete $suggestion->{$_} foreach qw<op suggested_by_anyone confirm>;
60
$op = 'else' unless $op;
62
$op = 'else' unless $op;
61
63
62
my ( $template, $borrowernumber, $cookie, @messages );
64
my ( $template, $borrowernumber, $cookie, @messages );
Lines 114-119 if ( $op eq 'else' ) { Link Here
114
    }
116
    }
115
}
117
}
116
118
119
if ( $op eq "add_validate" ) {
120
    $op = 'add_confirm';
121
    my $biblio = MarcRecordFromNewSuggestion($suggestion);
122
    if ( my ($duplicatebiblionumber, $duplicatetitle) = FindDuplicate($biblio) ) {
123
        push @messages, { type => 'error', code => 'biblio_exists', id => $duplicatebiblionumber, title => $duplicatetitle };
124
        $need_confirm = 1;
125
        $op = 'add';
126
    }
127
}
128
117
my $patrons_pending_suggestions_count = 0;
129
my $patrons_pending_suggestions_count = 0;
118
if ( $borrowernumber && C4::Context->preference("MaxOpenSuggestions") ne '' ) {
130
if ( $borrowernumber && C4::Context->preference("MaxOpenSuggestions") ne '' ) {
119
    $patrons_pending_suggestions_count = scalar @{ SearchSuggestion( { suggestedby => $borrowernumber, STATUS => 'ASKED' } ) } ;
131
    $patrons_pending_suggestions_count = scalar @{ SearchSuggestion( { suggestedby => $borrowernumber, STATUS => 'ASKED' } ) } ;
Lines 164-169 if ( $op eq "add_confirm" ) { Link Here
164
    $op = 'else';
176
    $op = 'else';
165
}
177
}
166
178
179
my $suggestions_loop = &SearchSuggestion({suggestedby => $suggestion->{suggestedby}});
167
if ( $op eq "delete_confirm" ) {
180
if ( $op eq "delete_confirm" ) {
168
    my @delete_field = $input->multi_param("delete_field");
181
    my @delete_field = $input->multi_param("delete_field");
169
    foreach my $delete_field (@delete_field) {
182
    foreach my $delete_field (@delete_field) {
Lines 228-233 $template->param( Link Here
228
    suggestionsview       => 1,
241
    suggestionsview       => 1,
229
    suggested_by_anyone   => $suggested_by_anyone,
242
    suggested_by_anyone   => $suggested_by_anyone,
230
    patrons_pending_suggestions_count => $patrons_pending_suggestions_count,
243
    patrons_pending_suggestions_count => $patrons_pending_suggestions_count,
244
    need_confirm => $need_confirm,
231
);
245
);
232
246
233
output_html_with_http_headers $input, $cookie, $template->output, undef, { force_no_caching => 1 };
247
output_html_with_http_headers $input, $cookie, $template->output, undef, { force_no_caching => 1 };
(-)a/t/db_dependent/Suggestions.t (-2 / +19 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use DateTime::Duration;
20
use DateTime::Duration;
21
use Test::More tests => 110;
21
use Test::More tests => 113;
22
use Test::Warn;
22
use Test::Warn;
23
23
24
use t::lib::Mocks;
24
use t::lib::Mocks;
Lines 422-427 ModSuggestion( $my_suggestion ); Link Here
422
$suggestion = GetSuggestion($my_suggestionid_test_budgetid);
422
$suggestion = GetSuggestion($my_suggestionid_test_budgetid);
423
is( $suggestion->{budgetid}, undef, 'NewSuggestion Should set budgetid to NULL if equals an empty string' );
423
is( $suggestion->{budgetid}, undef, 'NewSuggestion Should set budgetid to NULL if equals an empty string' );
424
424
425
my $suggestion2 = {
426
    title => "Cuisine d'automne",
427
    author => "Catherine",
428
    itemtype => "LIV"
429
};
430
431
my $record = MarcRecordFromNewSuggestion($suggestion2);
432
433
is("MARC::Record", ref($record), "MarcRecordFromNewSuggestion should return a MARC::Record object");
434
435
my ($title_tag, $title_subfield) = C4::Biblio::GetMarcFromKohaField('biblio.title', '');
436
437
is($record->field( $title_tag )->subfield( $title_subfield ), "Cuisine d'automne", "Record from suggestion title should be 'Cuisine d'automne'");
438
439
my ($author_tag, $author_subfield) = C4::Biblio::GetMarcFromKohaField('biblio.author', '');
440
441
is($record->field( $author_tag )->subfield( $author_subfield ), "Catherine", "Record from suggestion author should be 'Catherine'");
442
425
subtest 'GetUnprocessedSuggestions' => sub {
443
subtest 'GetUnprocessedSuggestions' => sub {
426
    plan tests => 11;
444
    plan tests => 11;
427
    $dbh->do(q|DELETE FROM suggestions|);
445
    $dbh->do(q|DELETE FROM suggestions|);
428
- 

Return to bug 14973