@@ -, +, @@ --- C4/Auth.pm | 1 + Koha/Misc/Files.pm | 174 ++++++++++++++++++++ acqui/invoice-files.pl | 132 +++++++++++++++ acqui/invoice.pl | 11 ++ installer/data/mysql/kohastructure.sql | 18 ++ installer/data/mysql/updatedatabase.pl | 22 +++ .../prog/en/modules/acqui/invoice-files.tt | 86 ++++++++++ .../intranet-tmpl/prog/en/modules/acqui/invoice.tt | 25 +++ .../en/modules/admin/preferences/acquisitions.pref | 6 + 9 files changed, 475 insertions(+) create mode 100644 Koha/Misc/Files.pm create mode 100755 acqui/invoice-files.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt --- a/C4/Auth.pm +++ a/C4/Auth.pm @@ -358,6 +358,7 @@ sub get_template_and_user { EnableBorrowerFiles => C4::Context->preference('EnableBorrowerFiles'), UseKohaPlugins => C4::Context->preference('UseKohaPlugins'), UseCourseReserves => C4::Context->preference("UseCourseReserves"), + AcqEnableFiles => C4::Context->preference('AcqEnableFiles'), ); } else { --- a/Koha/Misc/Files.pm +++ a/Koha/Misc/Files.pm @@ -0,0 +1,174 @@ +package Koha::Misc::Files; + +# This file is part of Koha. +# +# Copyright 2012 Kyle M Hall +# Copyright 2014 Jacek Ablewicz +# Based on Koha/Borrower/Files.pm by Kyle M Hall +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use strict; ## not needed if Modern::Perl, but perlcritic complains.. +use vars qw($VERSION); +$VERSION = '0.20'; + +use C4::Context; +use C4::Output; +use C4::Dates; +use C4::Debug; + +=head1 NAME + +Koha::Misc::Files - module for managing miscellaneous files +associated with records from arbitrary tables + +=cut + +sub new { + my ( $class, %args ) = @_; + + ( defined( $args{'tabletag'} ) && defined( $args{'recordid'} ) ) + || return (); + my $self = bless( {}, $class ); + + $self->{'table_tag'} = $args{'tabletag'}; + $self->{'record_id'} = $args{'recordid'}; + + return $self; +} + +=item GetFilesInfo() + + my $mf = Koha::Misc::Files->new( tabletag => $tablename, + recordid => $recordnumber); + my $files_hashref = $mf->GetFilesInfo + +=cut + +sub GetFilesInfo { + my $self = shift; + + my $dbh = C4::Context->dbh; + my $query = " + SELECT + file_id, + file_name, + file_type, + file_description, + date_uploaded + FROM misc_files + WHERE table_tag = ? AND record_id = ? + ORDER BY file_name, date_uploaded + "; + my $sth = $dbh->prepare($query); + $sth->execute( $self->{'table_tag'}, $self->{'record_id'} ); + return $sth->fetchall_arrayref( {} ); +} + +=item AddFile() + my $mf = Koha::Misc::Files->new( tabletag => $tablename, + recordid => $recordnumber); + $mf->AddFile( name => $filename, type => $mimetype, description => $description, content => $content ); +=cut + +sub AddFile { + my ( $self, %args ) = @_; + + my $name = $args{'name'}; + my $type = $args{'type'}; + my $description = $args{'description'}; + my $content = $args{'content'}; + + return unless ( $name && $content ); + + my $dbh = C4::Context->dbh; + my $query = " + INSERT INTO misc_files ( table_tag, record_id, file_name, file_type, file_description, file_content ) + VALUES ( ?,?,?,?,?,? ) + "; + my $sth = $dbh->prepare($query); + $sth->execute( $self->{'table_tag'}, $self->{'record_id'}, $name, $type, + $description, $content ); +} + +=item GetFile() + my $mf = Koha::Misc::Files->new( tabletag => $tablename, + recordid => $recordnumber); + ... + my $file = $mf->GetFile( id => $file_id ); +=cut + +sub GetFile { + my ( $self, %args ) = @_; + + my $file_id = $args{'id'}; + + my $dbh = C4::Context->dbh; + my $query = " + SELECT * FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ? + "; + my $sth = $dbh->prepare($query); + $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} ); + return $sth->fetchrow_hashref(); +} + +=item DelFile() + my $mf = Koha::Misc::Files->new( tabletag => $tablename, + recordid => $recordnumber); + ... + $mf->DelFile( id => $file_id ); +=cut + +sub DelFile { + my ( $self, %args ) = @_; + + my $file_id = $args{'id'}; + + my $dbh = C4::Context->dbh; + my $query = " + DELETE FROM misc_files WHERE file_id = ? AND table_tag = ? AND record_id = ? + "; + my $sth = $dbh->prepare($query); + $sth->execute( $file_id, $self->{'table_tag'}, $self->{'record_id'} ); +} + +=item DelAllFiles() + my $mf = Koha::Misc::Files->new( tabletag => $tablename, + recordid => $recordnumber); + $mf->DelAllFiles; +=cut + +sub DelAllFiles { + my ($self) = @_; + + my $dbh = C4::Context->dbh; + my $query = " + DELETE FROM misc_files WHERE table_tag = ? AND record_id = ? + "; + my $sth = $dbh->prepare($query); + $sth->execute( $self->{'table_tag'}, $self->{'record_id'} ); +} + +1; +__END__ + +=back + +=head1 AUTHOR + +Kyle M Hall +Jacek Ablewicz + +=cut --- a/acqui/invoice-files.pl +++ a/acqui/invoice-files.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Copyright 2014 Jacek Ablewicz +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +=head1 NAME + +invoice-files.pl + +=head1 DESCRIPTION + +Manage files associated with invoice + +=cut + +use strict; +use warnings; + +use CGI; +use C4::Auth; +use C4::Output; +use C4::Acquisition; +use C4::Debug; +use Koha::DateUtils; +use Koha::Misc::Files; + +my $input = new CGI; +my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( + { + template_name => 'acqui/invoice-files.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { 'acquisition' => '*' }, + debug => 1, + } +); + +my $invoiceid = $input->param('invoiceid'); +my $op = $input->param('op') // ''; + +$template->param( 'invoice_files' => 1 ); +my $mf = Koha::Misc::Files->new( tabletag => 'aqinvoices', recordid => $invoiceid ); + +if ( $op eq 'download' ) { + my $file_id = $input->param('file_id'); + my $file = $mf->GetFile( id => $file_id ); + + my $fname = $file->{'file_name'}; + my $ftype = $file->{'file_type'}; + if ($input->param('view') && ($ftype =~ /^image\//i || $fname =~ /\.pdf/i)) { + $fname =~ /\.pdf/i && do { $ftype='application/pdf'; }; + print $input->header( + -type => $ftype, + -charset => 'utf-8', + ); + } else { + print $input->header( + -type => $file->{'file_type'}, + -charset => 'utf-8', + -attachment => $file->{'file_name'} + ); + } + print $file->{'file_content'}; +} +else { + my $details = GetInvoiceDetails($invoiceid); + $template->param( + invoiceid => $details->{'invoiceid'}, + invoicenumber => $details->{'invoicenumber'}, + suppliername => $details->{'suppliername'}, + booksellerid => $details->{'booksellerid'}, + datereceived => $details->{'datereceived'}, + ); + my %errors; + + if ( $op eq 'upload' ) { + my $uploaded_file = $input->upload('uploadfile'); + + if ($uploaded_file) { + my $filename = $input->param('uploadfile'); + my $mimetype = $input->uploadInfo($filename)->{'Content-Type'}; + + $errors{'empty_upload'} = 1 if ( -z $uploaded_file ); + + if (%errors) { + $template->param( errors => %errors ); + } + else { + my $file_content; + while (<$uploaded_file>) { + $file_content .= $_; + } + if ($mimetype =~ /^application\/(force-download|unknown)$/i && $filename =~ /\.pdf$/) { + $mimetype = 'application/pdf'; + } + $mf->AddFile( + name => $filename, + type => $mimetype, + content => $file_content, + description => $input->param('description'), + ); + } + } + else { + $errors{'no_file'} = 1; + } + } elsif ( $op eq 'delete' ) { + $mf->DelFile( id => $input->param('file_id') ); + } + + $template->param( + files => $mf->GetFilesInfo(), + errors => \%errors + ); + + output_html_with_http_headers $input, $cookie, $template->output; +} --- a/acqui/invoice.pl +++ a/acqui/invoice.pl @@ -35,6 +35,7 @@ use C4::Output; use C4::Acquisition; use C4::Bookseller qw/GetBookSellerFromId/; use C4::Budgets; +use Koha::Misc::Files; my $input = new CGI; my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( @@ -91,6 +92,9 @@ elsif ( $op && $op eq 'mod' ) { } elsif ( $op && $op eq 'delete' ) { DelInvoice($invoiceid); + C4::Context->preference('AcqEnableFiles') + && $invoiceid && Koha::Misc::Files->new( + tabletag => 'aqinvoices', recordid => $invoiceid )->DelAllFiles(); my $referer = $input->param('referer') || 'invoices.pl'; if ($referer) { print $input->redirect($referer); @@ -209,6 +213,13 @@ $template->param( budgets_loop => \@budgets_loop, ); +{ + C4::Context->preference('AcqEnableFiles') || last; + my $mf = Koha::Misc::Files->new( + tabletag => 'aqinvoices', recordid => $invoiceid ); + defined( $mf ) && $template->param( files => $mf->GetFilesInfo() ); +} + sub get_infos { my $order = shift; my $bookseller = shift; --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -3393,6 +3393,24 @@ CREATE TABLE IF NOT EXISTS marc_modification_template_actions ( CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table structure for table `misc_files` +-- + +CREATE TABLE IF NOT EXISTS `misc_files` ( -- miscellaneous files attached to records from various tables + `file_id` int(11) NOT NULL AUTO_INCREMENT, -- unique id for the file record + `table_tag` varchar(255) NOT NULL, -- usually table name, or arbitrary unique tag + `record_id` int(11) NOT NULL, -- record id from the table this file is associated to + `file_name` varchar(255) NOT NULL, -- file name + `file_type` varchar(255) NOT NULL, -- MIME type of the file + `file_description` varchar(255) DEFAULT NULL, -- description given to the file + `file_content` longblob NOT NULL, -- file content + `date_uploaded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, -- date and time the file was added + PRIMARY KEY (`file_id`), + KEY `table_tag` (`table_tag`), + KEY `record_id` (`record_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -7953,6 +7953,28 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.15.00.XXX"; +if (CheckVersion($DBversion)) { + $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')"); + $dbh->do(" +CREATE TABLE IF NOT EXISTS `misc_files` ( + `file_id` int(11) NOT NULL AUTO_INCREMENT, + `table_tag` varchar(255) NOT NULL, + `record_id` int(11) NOT NULL, + `file_name` varchar(255) NOT NULL, + `file_type` varchar(255) NOT NULL, + `file_description` varchar(255) DEFAULT NULL, + `file_content` longblob NOT NULL, -- file content + `date_uploaded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`file_id`), + KEY `table_tag` (`table_tag`), + KEY `record_id` (`record_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + "); + print "Upgrade to $DBversion done (Bug 3050 - Add an option to upload scanned invoices)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt @@ -0,0 +1,86 @@ +[% USE KohaDates %] + +[% INCLUDE 'doc-head-open.inc' %] +Koha › Acquisitions › Invoice › Files + +[% INCLUDE 'doc-head-close.inc' %] + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'acquisitions-search.inc' %] + + + +
+ +
+
+
+

Files for invoice: [% invoicenumber %]

+ +

Vendor: [% suppliername %]

+ + [% IF errors %] +
+ [% IF errors.empty_upload %]The file you are attempting to upload has no contents.[% END %] + [% IF errors.no_file %]You did not select a file to upload.[% END %] +
+ [% END %] + + [% IF ( files ) %] + + + + + + + + + + + + + + [% FOREACH f IN files %] + + + + + + + + + [% END %] + +
NameTypeDescriptionUploaded  
[% f.file_name %][% f.file_type %][% f.file_description %][% f.date_uploaded | $KohaDates %]DeleteDownload
+ [% ELSE %] +
+

This invoice has no files attached.

+
+ [% END %] + +
+
+ Upload New File +
    +
  1. + + + + +
  2. + +
  3. + +
+
+
+
+ +
+
+
+ [% INCLUDE 'acquisitions-menu.inc' %] +
+
+[% INCLUDE 'intranet-bottom.inc' %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt @@ -89,6 +89,7 @@

Go to receipt page + [% IF ( AcqEnableFiles ) %]| Manage invoice files[% END %]

Invoice details

[% IF orders_loop.size %] @@ -169,6 +170,30 @@ [% ELSE %]

No orders yet

[% END %] + [% IF ( AcqEnableFiles && files ) %] +
+

Files attached to invoice

+ + + + + + + + + + + [% FOREACH f IN files %] + + + + + + + [% END %] + +
NameTypeDescriptionUploaded
[% f.file_name %][% f.file_type %][% f.file_description %][% f.date_uploaded | $KohaDates %]
+ [% END %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref @@ -45,6 +45,12 @@ Acquisitions: - - Upon receiving items, update their subfields if they were created when placing an order (e.g. o=5|a="foo bar"). - pref: AcqItemSetSubfieldsWhenReceived + - + - pref: AcqEnableFiles + choices: + yes: Do + no: "Don't" + - enable the ability to upload and attach arbitrary files to invoices. Printing: - --