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

(-)a/C4/Auth.pm (+1 lines)
Lines 358-363 sub get_template_and_user { Link Here
358
            EnableBorrowerFiles         => C4::Context->preference('EnableBorrowerFiles'),
358
            EnableBorrowerFiles         => C4::Context->preference('EnableBorrowerFiles'),
359
            UseKohaPlugins              => C4::Context->preference('UseKohaPlugins'),
359
            UseKohaPlugins              => C4::Context->preference('UseKohaPlugins'),
360
            UseCourseReserves            => C4::Context->preference("UseCourseReserves"),
360
            UseCourseReserves            => C4::Context->preference("UseCourseReserves"),
361
            AcqEnableFiles              => C4::Context->preference('AcqEnableFiles'),
361
        );
362
        );
362
    }
363
    }
363
    else {
364
    else {
(-)a/Koha/Misc/Files.pm (+174 lines)
Line 0 Link Here
1
package Koha::Misc::Files;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 Kyle M Hall
6
# Copyright 2014 Jacek Ablewicz
7
# Based on Koha/Borrower/Files.pm by Kyle M Hall
8
#
9
# Koha is free software; you can redistribute it and/or modify it
10
# under the terms of the GNU General Public License as published by
11
# the Free Software Foundation; either version 3 of the License, or
12
# (at your option) any later version.
13
#
14
# Koha is distributed in the hope that it will be useful, but
15
# WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22
use Modern::Perl;
23
use strict; ## not needed if Modern::Perl, but perlcritic complains..
24
use vars qw($VERSION);
25
$VERSION = '0.20';
26
27
use C4::Context;
28
use C4::Output;
29
use C4::Dates;
30
use C4::Debug;
31
32
=head1 NAME
33
34
Koha::Misc::Files - module for managing miscellaneous files
35
associated with records from arbitrary tables
36
37
=cut
38
39
sub new {
40
    my ( $class, %args ) = @_;
41
42
    ( defined( $args{'tabletag'} ) && defined( $args{'recordid'} ) )
43
      || return ();
44
    my $self = bless( {}, $class );
45
46
    $self->{'table_tag'} = $args{'tabletag'};
47
    $self->{'record_id'} = $args{'recordid'};
48
49
    return $self;
50
}
51
52
=item GetFilesInfo()
53
54
    my $mf = Koha::Misc::Files->new( tabletag => $tablename,
55
        recordid => $recordnumber);
56
    my $files_hashref = $mf->GetFilesInfo
57
58
=cut
59
60
sub GetFilesInfo {
61
    my $self = shift;
62
63
    my $dbh   = C4::Context->dbh;
64
    my $query = "
65
        SELECT
66
            file_id,
67
            file_name,
68
            file_type,
69
            file_description,
70
            date_uploaded
71
        FROM misc_files
72
        WHERE table_tag = ? AND record_id = ?
73
        ORDER BY file_name, date_uploaded
74
    ";
75
    my $sth = $dbh->prepare($query);
76
    $sth->execute( $self->{'table_tag'}, $self->{'record_id'} );
77
    return $sth->fetchall_arrayref( {} );
78
}
79
80
=item AddFile()
81
    my $mf = Koha::Misc::Files->new( tabletag => $tablename,
82
        recordid => $recordnumber);
83
    $mf->AddFile( name => $filename, type => $mimetype, description => $description, content => $content );
84
=cut
85
86
sub AddFile {
87
    my ( $self, %args ) = @_;
88
89
    my $name        = $args{'name'};
90
    my $type        = $args{'type'};
91
    my $description = $args{'description'};
92
    my $content     = $args{'content'};
93
94
    return unless ( $name && $content );
95
96
    my $dbh   = C4::Context->dbh;
97
    my $query = "
98
        INSERT INTO misc_files ( table_tag, record_id, file_name, file_type, file_description, file_content )
99
        VALUES ( ?,?,?,?,?,? )
100
    ";
101
    my $sth = $dbh->prepare($query);
102
    $sth->execute( $self->{'table_tag'}, $self->{'record_id'}, $name, $type,
103
        $description, $content );
104
}
105
106
=item GetFile()
107
    my $mf = Koha::Misc::Files->new( tabletag => $tablename,
108
        recordid => $recordnumber);
109
    ...
110
    my $file = $mf->GetFile( id => $file_id );
111
=cut
112
113
sub GetFile {
114
    my ( $self, %args ) = @_;
115
116
    my $file_id = $args{'id'};
117
118
    my $dbh   = C4::Context->dbh;
119
    my $query = "
120
        SELECT * FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ?
121
    ";
122
    my $sth = $dbh->prepare($query);
123
    $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} );
124
    return $sth->fetchrow_hashref();
125
}
126
127
=item DelFile()
128
    my $mf = Koha::Misc::Files->new( tabletag => $tablename,
129
        recordid => $recordnumber);
130
    ...
131
    $mf->DelFile( id => $file_id );
132
=cut
133
134
sub DelFile {
135
    my ( $self, %args ) = @_;
136
137
    my $file_id = $args{'id'};
138
139
    my $dbh   = C4::Context->dbh;
140
    my $query = "
141
        DELETE FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ?
142
    ";
143
    my $sth = $dbh->prepare($query);
144
    $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} );
145
}
146
147
=item DelAllFiles()
148
    my $mf = Koha::Misc::Files->new( tabletag => $tablename,
149
        recordid => $recordnumber);
150
    $mf->DelAllFiles;
151
=cut
152
153
sub DelAllFiles {
154
    my ($self) = @_;
155
156
    my $dbh   = C4::Context->dbh;
157
    my $query = "
158
        DELETE FROM misc_files WHERE table_tag = ? AND record_id = ?
159
    ";
160
    my $sth = $dbh->prepare($query);
161
    $sth->execute( $self->{'table_tag'}, $self->{'record_id'} );
162
}
163
164
1;
165
__END__
166
167
=back
168
169
=head1 AUTHOR
170
171
Kyle M Hall <kyle.m.hall@gmail.com>
172
Jacek Ablewicz <ablewicz@gmail.com>
173
174
=cut
(-)a/acqui/invoice-files.pl (+132 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Copyright 2014 Jacek Ablewicz
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
=head1 NAME
21
22
invoice-files.pl
23
24
=head1 DESCRIPTION
25
26
Manage files associated with invoice
27
28
=cut
29
30
use strict;
31
use warnings;
32
33
use CGI;
34
use C4::Auth;
35
use C4::Output;
36
use C4::Acquisition;
37
use C4::Debug;
38
use Koha::DateUtils;
39
use Koha::Misc::Files;
40
41
my $input = new CGI;
42
my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
43
    {
44
        template_name   => 'acqui/invoice-files.tmpl',
45
        query           => $input,
46
        type            => 'intranet',
47
        authnotrequired => 0,
48
        flagsrequired   => { 'acquisition' => '*' },
49
        debug           => 1,
50
    }
51
);
52
53
my $invoiceid = $input->param('invoiceid');
54
my $op = $input->param('op') // '';
55
56
$template->param( 'invoice_files' => 1 );
57
my $mf = Koha::Misc::Files->new( tabletag => 'aqinvoices', recordid => $invoiceid );
58
59
if ( $op eq 'download' ) {
60
    my $file_id = $input->param('file_id');
61
    my $file = $mf->GetFile( id => $file_id );
62
63
    my $fname = $file->{'file_name'};
64
    my $ftype = $file->{'file_type'};
65
    if ($input->param('view') && ($ftype =~ /^image\//i || $fname =~ /\.pdf/i)) {
66
        $fname =~ /\.pdf/i && do { $ftype='application/pdf'; };
67
        print $input->header(
68
            -type       => $ftype,
69
            -charset    => 'utf-8',
70
        );
71
    } else {
72
        print $input->header(
73
            -type       => $file->{'file_type'},
74
            -charset    => 'utf-8',
75
            -attachment => $file->{'file_name'}
76
        );
77
    }
78
    print $file->{'file_content'};
79
}
80
else {
81
    my $details = GetInvoiceDetails($invoiceid);
82
    $template->param(
83
        invoiceid        => $details->{'invoiceid'},
84
        invoicenumber    => $details->{'invoicenumber'},
85
        suppliername     => $details->{'suppliername'},
86
        booksellerid     => $details->{'booksellerid'},
87
        datereceived     => $details->{'datereceived'},
88
    );
89
    my %errors;
90
91
    if ( $op eq 'upload' ) {
92
        my $uploaded_file = $input->upload('uploadfile');
93
94
        if ($uploaded_file) {
95
            my $filename = $input->param('uploadfile');
96
            my $mimetype = $input->uploadInfo($filename)->{'Content-Type'};
97
98
            $errors{'empty_upload'} = 1 if ( -z $uploaded_file );
99
100
            if (%errors) {
101
                $template->param( errors => %errors );
102
            }
103
            else {
104
                my $file_content;
105
                while (<$uploaded_file>) {
106
                    $file_content .= $_;
107
                }
108
                if ($mimetype =~ /^application\/(force-download|unknown)$/i && $filename =~ /\.pdf$/) {
109
                    $mimetype = 'application/pdf';
110
                }
111
                $mf->AddFile(
112
                    name    => $filename,
113
                    type    => $mimetype,
114
                    content => $file_content,
115
                    description => $input->param('description'),
116
                );
117
            }
118
        }
119
        else {
120
            $errors{'no_file'} = 1;
121
        }
122
    } elsif ( $op eq 'delete' ) {
123
        $mf->DelFile( id => $input->param('file_id') );
124
    }
125
126
    $template->param(
127
        files => $mf->GetFilesInfo(),
128
        errors => \%errors
129
    );
130
    
131
    output_html_with_http_headers $input, $cookie, $template->output;
132
}
(-)a/acqui/invoice.pl (+11 lines)
Lines 35-40 use C4::Output; Link Here
35
use C4::Acquisition;
35
use C4::Acquisition;
36
use C4::Bookseller qw/GetBookSellerFromId/;
36
use C4::Bookseller qw/GetBookSellerFromId/;
37
use C4::Budgets;
37
use C4::Budgets;
38
use Koha::Misc::Files;
38
39
39
my $input = new CGI;
40
my $input = new CGI;
40
my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
41
my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
Lines 91-96 elsif ( $op && $op eq 'mod' ) { Link Here
91
}
92
}
92
elsif ( $op && $op eq 'delete' ) {
93
elsif ( $op && $op eq 'delete' ) {
93
    DelInvoice($invoiceid);
94
    DelInvoice($invoiceid);
95
    C4::Context->preference('AcqEnableFiles')
96
      && $invoiceid && Koha::Misc::Files->new(
97
        tabletag => 'aqinvoices', recordid => $invoiceid )->DelAllFiles();
94
    my $referer = $input->param('referer') || 'invoices.pl';
98
    my $referer = $input->param('referer') || 'invoices.pl';
95
    if ($referer) {
99
    if ($referer) {
96
        print $input->redirect($referer);
100
        print $input->redirect($referer);
Lines 209-214 $template->param( Link Here
209
    budgets_loop             => \@budgets_loop,
213
    budgets_loop             => \@budgets_loop,
210
);
214
);
211
215
216
{
217
    C4::Context->preference('AcqEnableFiles') || last;
218
    my $mf = Koha::Misc::Files->new(
219
        tabletag => 'aqinvoices', recordid => $invoiceid );
220
    defined( $mf ) && $template->param( files => $mf->GetFilesInfo() );
221
}
222
212
sub get_infos {
223
sub get_infos {
213
    my $order      = shift;
224
    my $order      = shift;
214
    my $bookseller = shift;
225
    my $bookseller = shift;
(-)a/installer/data/mysql/kohastructure.sql (+18 lines)
Lines 3393-3398 CREATE TABLE IF NOT EXISTS marc_modification_template_actions ( Link Here
3393
  CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE
3393
  CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE
3394
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
3394
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
3395
3395
3396
--
3397
-- Table structure for table `misc_files`
3398
--
3399
3400
CREATE TABLE IF NOT EXISTS `misc_files` ( -- miscellaneous files attached to records from various tables
3401
  `file_id` int(11) NOT NULL AUTO_INCREMENT, -- unique id for the file record
3402
  `table_tag` varchar(255) NOT NULL, -- usually table name, or arbitrary unique tag
3403
  `record_id` int(11) NOT NULL, -- record id from the table this file is associated to
3404
  `file_name` varchar(255) NOT NULL, -- file name
3405
  `file_type` varchar(255) NOT NULL, -- MIME type of the file
3406
  `file_description` varchar(255) DEFAULT NULL, -- description given to the file
3407
  `file_content` longblob NOT NULL, -- file content
3408
  `date_uploaded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- date and time the file was added
3409
  PRIMARY KEY (`file_id`),
3410
  KEY `table_tag` (`table_tag`),
3411
  KEY `record_id` (`record_id`)
3412
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3413
3396
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
3414
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
3397
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
3415
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
3398
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
3416
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
(-)a/installer/data/mysql/updatedatabase.pl (+22 lines)
Lines 7953-7958 if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
7953
    SetVersion($DBversion);
7953
    SetVersion($DBversion);
7954
}
7954
}
7955
7955
7956
$DBversion = "3.15.00.XXX";
7957
if (CheckVersion($DBversion)) {
7958
    $dbh->do("INSERT INTO systempreferences (variable,value,explanation,type) VALUES('AcqEnableFiles','0','If enabled, allows librarians to upload and attach arbitrary files to invoice records.','YesNo')");
7959
    $dbh->do("
7960
CREATE TABLE IF NOT EXISTS `misc_files` (
7961
  `file_id` int(11) NOT NULL AUTO_INCREMENT,
7962
  `table_tag` varchar(255) NOT NULL,
7963
  `record_id` int(11) NOT NULL,
7964
  `file_name` varchar(255) NOT NULL,
7965
  `file_type` varchar(255) NOT NULL,
7966
  `file_description` varchar(255) DEFAULT NULL,
7967
  `file_content` longblob NOT NULL, -- file content
7968
  `date_uploaded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
7969
  PRIMARY KEY (`file_id`),
7970
  KEY `table_tag` (`table_tag`),
7971
  KEY `record_id` (`record_id`)
7972
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
7973
    ");
7974
    print "Upgrade to $DBversion done (Bug 3050 - Add an option to upload scanned invoices)\n";
7975
    SetVersion($DBversion);
7976
}
7977
7956
=head1 FUNCTIONS
7978
=head1 FUNCTIONS
7957
7979
7958
=head2 TableExists($table)
7980
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt (+86 lines)
Line 0 Link Here
1
[% USE KohaDates %]
2
3
[% INCLUDE 'doc-head-open.inc' %]
4
<title>Koha &rsaquo; Acquisitions &rsaquo; Invoice &rsaquo; Files</title>
5
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
6
[% INCLUDE 'doc-head-close.inc' %]
7
</head>
8
<body>
9
[% INCLUDE 'header.inc' %]
10
[% INCLUDE 'acquisitions-search.inc' %]
11
12
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/acqui/acqui-home.pl">Acquisitions</a> &rsaquo; <a href="/cgi-bin/koha/acqui/invoices.pl">Invoices</a> &rsaquo; <a href="/cgi-bin/koha/acqui/invoice.pl?invoiceid=[% invoiceid %]">[% invoicenumber %]</a> &rsaquo; Files</div>
13
14
<div id="doc3" class="yui-t2">
15
16
<div id="bd">
17
  <div id="yui-main">
18
    <div class="yui-b">
19
      <h1>Files for invoice: [% invoicenumber %]</h1>
20
21
      <p>Vendor: <a href="/cgi-bin/koha/acqui/supplier.pl?booksellerid=[% booksellerid %]">[% suppliername %]</a></p>
22
23
                [% IF errors %]
24
                    <div class="dialog alert">
25
                        [% IF errors.empty_upload %]The file you are attempting to upload has no contents.[% END %]
26
                        [% IF errors.no_file %]You did not select a file to upload.[% END %]
27
                    </div>
28
                [% END %]
29
30
                [% IF ( files ) %]
31
                <table>
32
                    <thead>
33
                        <tr>
34
                            <th>Name</th>
35
                            <th>Type</th>
36
                            <th>Description</th>
37
                            <th>Uploaded</th>
38
                            <th>&nbsp;</th>
39
                            <th>&nbsp;</th>
40
                        </tr>
41
                    </thead>
42
43
                    <tbody>
44
                        [% FOREACH f IN files %]
45
                            <tr>
46
                                 <td><a href="?invoiceid=[% invoiceid %]&amp;op=download&amp;view=1&amp;file_id=[% f.file_id %]">[% f.file_name %]</a></td>
47
                                 <td>[% f.file_type %]</td>
48
                                 <td>[% f.file_description %]</td>
49
                                 <td>[% f.date_uploaded | $KohaDates %]</td>
50
                                 <td><a href="?invoiceid=[% invoiceid %]&amp;op=delete&amp;file_id=[% f.file_id %]">Delete</a></td>
51
                                 <td><a href="?invoiceid=[% invoiceid %]&amp;op=download&amp;file_id=[% f.file_id %]">Download</a></td>
52
                            </tr>
53
                        [% END %]
54
                    </tbody>
55
                </table>
56
                [% ELSE %]
57
                <div class="dialog message">
58
                    <p>This invoice has no files attached.</p>
59
                </div>
60
                [% END %]
61
62
                <form method="post" action="/cgi-bin/koha/acqui/invoice-files.pl" enctype="multipart/form-data">
63
                    <fieldset class="rows">
64
                        <legend>Upload New File</legend>
65
                        <ol>
66
                        <li><input type="hidden" name="op" value="upload" />
67
                        <input type="hidden" name="invoiceid" value="[% invoiceid %]" />
68
                        <input type="hidden" name="MAX_FILE_SIZE" value="9000000" />
69
70
                        <label for="description">Description:</label>
71
                        <input name="description" id="description" type="text" /></li>
72
73
                        <li><label for="uploadfile">File:</label><input name="uploadfile" type="file" id="uploadfile" /></li>
74
75
                        </ol>
76
                        <fieldset class="action"><input name="upload" type="submit" id="upload" value="Upload File" /></fieldset>
77
                    </fieldset>
78
                </form>
79
80
    </div>
81
  </div>
82
  <div class="yui-b">
83
    [% INCLUDE 'acquisitions-menu.inc' %]
84
  </div>
85
</div>
86
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt (+25 lines)
Lines 89-94 Link Here
89
      </form>
89
      </form>
90
      <p>
90
      <p>
91
          <a href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid %]">Go to receipt page</a>
91
          <a href="/cgi-bin/koha/acqui/parcel.pl?invoiceid=[% invoiceid %]">Go to receipt page</a>
92
          [% IF ( AcqEnableFiles ) %]| <a href="/cgi-bin/koha/acqui/invoice-files.pl?invoiceid=[% invoiceid %]">Manage invoice files</a>[% END %]
92
      </p>
93
      </p>
93
      <h2>Invoice details</h2>
94
      <h2>Invoice details</h2>
94
      [% IF orders_loop.size %]
95
      [% IF orders_loop.size %]
Lines 169-174 Link Here
169
        [% ELSE %]
170
        [% ELSE %]
170
            <div class="dialog message"><p>No orders yet</p></div>
171
            <div class="dialog message"><p>No orders yet</p></div>
171
        [% END %]
172
        [% END %]
173
        [% IF ( AcqEnableFiles && files ) %]
174
            <br>
175
            <h2>Files attached to invoice</h2>
176
            <table>
177
                <thead>
178
                    <tr>
179
                        <th>Name</th>
180
                        <th>Type</th>
181
                        <th>Description</th>
182
                        <th>Uploaded</th>
183
                    </tr>
184
                </thead>
185
                <tbody>
186
                [% FOREACH f IN files %]
187
                    <tr>
188
                         <td><a href="/cgi-bin/koha/acqui/invoice-files.pl?invoiceid=[% invoiceid %]&amp;op=download&amp;view=1&amp;file_id=[% f.file_id %]">[% f.file_name %]</a></td>
189
                         <td>[% f.file_type %]</td>
190
                         <td>[% f.file_description %]</td>
191
                         <td>[% f.date_uploaded | $KohaDates %]</td>
192
                    </tr>
193
                [% END %]
194
                </tbody>
195
            </table>
196
        [% END %]
172
    </div>
197
    </div>
173
  </div>
198
  </div>
174
  <div class="yui-b">
199
  <div class="yui-b">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref (-1 / +6 lines)
Lines 45-50 Acquisitions: Link Here
45
        -
45
        -
46
            - Upon receiving items, update their subfields if they were created when placing an order (e.g. o=5|a="foo bar").
46
            - Upon receiving items, update their subfields if they were created when placing an order (e.g. o=5|a="foo bar").
47
            - pref: AcqItemSetSubfieldsWhenReceived
47
            - pref: AcqItemSetSubfieldsWhenReceived
48
        -
49
            - pref: AcqEnableFiles
50
              choices:
51
                  yes: Do
52
                  no: "Don't"
53
            - enable the ability to upload and attach arbitrary files to invoices.
48
54
49
    Printing:
55
    Printing:
50
        -
56
        -
51
- 

Return to bug 3050