Browse Source

MT 1587 : CSV export for cart and shelves, with the ability to define different export profiles

Signed-off-by: Henri-Damien LAURENT <henridamien.laurent@biblibre.com>
3.2.x
Henri-Damien LAURENT 13 years ago
parent
commit
a7ccfbc629
  1. 80
      C4/Csv.pm
  2. 98
      C4/Record.pm
  3. 3
      installer/data/mysql/en/mandatory/userpermissions.sql
  4. 3
      installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql
  5. 8
      installer/data/mysql/updatedatabase.pl
  6. 98
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/csv-profiles.tmpl
  7. 6
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tmpl
  8. 4
      koha-tmpl/opac-tmpl/prog/en/modules/opac-downloadcart.tmpl
  9. 4
      koha-tmpl/opac-tmpl/prog/en/modules/opac-downloadshelf.tmpl
  10. 10
      opac/opac-downloadcart.pl
  11. 11
      opac/opac-downloadshelf.pl
  12. 121
      tools/csv-profiles.pl

80
C4/Csv.pm

@ -0,0 +1,80 @@
package C4::Csv;
# Copyright 2008 BibLibre
#
# This file is part of Koha.
#
# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
#
#
use C4::Context;
use vars qw($VERSION @ISA @EXPORT);
# set the version for version checking
$VERSION = 3.00;
@ISA = qw(Exporter);
# only export API methods
@EXPORT = qw(
&GetCsvProfiles
&GetCsvProfilesLoop
&GetMarcFieldsForCsv
);
my $dbh = C4::Context->dbh;
# Returns all informations about csv profiles
sub GetCsvProfiles {
my $query = "SELECT * FROM export_format";
$sth = $dbh->prepare($query);
$sth->execute;
$sth->fetchall_arrayref({});
}
# Returns fields to extract for the given csv profile
sub GetMarcFieldsForCsv {
my ($id) = @_;
my $query = "SELECT marcfields FROM export_format WHERE export_format_id=?";
$sth = $dbh->prepare($query);
$sth->execute($id);
return ($sth->fetchrow_hashref)->{marcfields};
}
# Returns informations aboout csv profiles suitable for html templates
sub GetCsvProfilesLoop {
# List of existing profiles
my $sth;
my $query = "SELECT export_format_id, profile FROM export_format";
$sth = $dbh->prepare($query);
$sth->execute();
return $sth->fetchall_arrayref({});
}
1;

98
C4/Record.pm

@ -29,6 +29,9 @@ use Biblio::EndnoteStyle;
use Unicode::Normalize; # _entity_encode
use XML::LibXSLT;
use XML::LibXML;
use C4::Biblio; #marc2bibtex
use C4::Csv; #marc2csv
use Text::CSV; #marc2csv
use vars qw($VERSION @ISA @EXPORT);
@ -46,6 +49,8 @@ $VERSION = 3.00;
&marcxml2marc
&marc2dcxml
&marc2modsxml
&marc2bibtex
&marc2csv
&html2marcxml
&html2marc
@ -322,6 +327,99 @@ sub marc2endnote {
}
=head2 marc2csv - Convert from UNIMARC to CSV
=over 4
my ($csv) = marc2csv($record, $csvprofileid);
Returns a CSV scalar
=over 2
C<$record> - a MARC::Record object
C<$csvprofileid> - the id of the CSV profile to use for the export (see export_format.export_format_id and the GetCsvProfiles function in C4::Csv)
=back
=back
=cut
sub marc2csv {
my ($record, $id, $header) = @_;
my $output;
my $csv = Text::CSV->new();
# Get the information about the csv profile
my $marcfieldslist = GetMarcFieldsForCsv($id);
# Getting the marcfields as an array
my @marcfields = split('\|', $marcfieldslist);
# If we have to insert the headers
if ($header) {
my @marcfieldsheaders;
my $dbh = C4::Context->dbh;
# For each field or subfield
foreach (@marcfields) {
# We get the matching tag name
if (index($_, '$') > 0) {
my ($fieldtag, $subfieldtag) = split('\$', $_);
my $query = "SELECT liblibrarian FROM marc_subfield_structure WHERE tagfield=? AND tagsubfield=?";
my $sth = $dbh->prepare($query);
$sth->execute($fieldtag, $subfieldtag);
my @results = $sth->fetchrow_array();
push @marcfieldsheaders, @results[0];
} else {
my $query = "SELECT liblibrarian FROM marc_tag_structure WHERE tagfield=?";
my $sth = $dbh->prepare($query);
$sth->execute($_);
my @results = $sth->fetchrow_array();
push @marcfieldsheaders, @results[0];
}
}
$csv->combine(@marcfieldsheaders);
$output = $csv->string() . "\n";
}
# For each marcfield to export
my @fieldstab;
foreach my $marcfield (@marcfields) {
# If it is a subfield
if (index($marcfield, '$') > 0) {
my ($fieldtag, $subfieldtag) = split('\$', $marcfield);
my @fields = $record->field($fieldtag);
my @tmpfields;
# For each field
foreach my $field (@fields) {
# We take every matching subfield
my @subfields = $field->subfield($subfieldtag);
foreach my $subfield (@subfields) {
push @tmpfields, $subfield;
}
}
push (@fieldstab, join(',', @tmpfields));
# Or a field
} else {
my @fields = ($record->field($marcfield));
push (@fieldstab, join(',', map($_->as_string(), @fields)));
}
};
$csv->combine(@fieldstab);
$output .= $csv->string() . "\n";
return $output;
}
=head2 html2marcxml

3
installer/data/mysql/en/mandatory/userpermissions.sql

@ -18,6 +18,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(13, 'schedule_tasks', 'Schedule tasks to run'),
(13, 'batchmod', 'Perform batch modification of items'),
(13, 'batchdel', 'Perform batch deletion of items'),
(13, 'manage_csv_profiles', 'Manage CSV export profiles')
(11, 'vendors_manage', 'Manage vendors'),
(11, 'contracts_manage', 'Manage contracts'),
(11, 'period_manage', 'Manage periods'),
@ -28,4 +29,4 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(11, 'group_manage', 'Manage orders & basketgroups'),
(11, 'order_receive', 'Manage orders & basket'),
(11, 'budget_add_del', 'Add and delete budgets (but cant modify budgets)')
;
;

3
installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql

@ -26,4 +26,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(11, 'group_manage', 'Gérer les commandes et les bons de commande'),
(11, 'order_receive', 'Gérer les réceptions')
(11, 'budget_add_del', 'Ajouter et supprimer les budgets (mais pas modifier)')
(13, 'manage_csv_profiles', 'Manage CSV export profiles')
(13, 'batch_mod', 'Modification Par lot des exemplaires')
(13, 'batch_del', 'Suppression par lot des exemplaires')
;

8
installer/data/mysql/updatedatabase.pl

@ -2688,6 +2688,13 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
print "Upgrade to $DBversion done ( Added ShowPatronImageInWebBasedSelfCheck system preference )\n";
SetVersion ($DBversion);
}
$DBversion = "3.01.00.062";
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
$dbh->do("INSERT INTO permissions (module_bit, code, description) VALUES ( 13, 'manage_csv_profiles', 'Manage CSV export profiles')");
print "Upgrade to $DBversion done (added permissions for csv export profiles)\n";
}
=item
Acquisitions update
@ -3032,6 +3039,7 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
}
=item DropAllForeignKeys($table)
Drop all foreign keys of the table $table

98
koha-tmpl/intranet-tmpl/prog/en/modules/tools/csv-profiles.tmpl

@ -0,0 +1,98 @@
<!-- TMPL_INCLUDE NAME="doc-head-open.inc" -->
<title>Koha &rsaquo; Catalog &rsaquo; Profile for CSV export</title>
<!-- TMPL_INCLUDE NAME="doc-head-close.inc" -->
<script language="Javascript" type="text/javascript">
function reloadPage(p) {
var id = p.value;
if (id != 0) { document.location = "/cgi-bin/koha/tools/csv-profiles.pl?id=" + id; }
}
</script>
</head>
<body>
<!-- TMPL_INCLUDE NAME="header.inc" -->
<!-- TMPL_INCLUDE NAME="cat-search.inc" -->
<div id="breadcrumbs">
<a href="/cgi-bin/koha/mainpage.pl">Home</a>
&rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a>
&rsaquo; New profile for CSV export
</div>
<div id="doc3" class="yui-t2">
<div id="bd">
<div id="yui-main">
<div class="yui-b">
<!-- TMPL_IF EXPR="success || error" -->
<!-- TMPL_IF NAME="success" -->
<!-- TMPL_IF EXPR="action eq 'create'" --><p>The new CSV profile "<!-- TMPL_VAR NAME="profile_name" -->" has been successfully created.</p><!-- /TMPL_IF -->
<!-- TMPL_IF EXPR="action eq 'edit'" --><p>The CSV profile has been successfully modified.</p><!-- /TMPL_IF -->
<!-- TMPL_IF EXPR="action eq 'delete'" --><p>The CSV profile has been successfully deleted.</p><!-- /TMPL_IF -->
<!-- TMPL_ELSE -->
<!-- TMPL_IF EXPR="action eq 'create'" --><p class="error">The new CSV profile "<!-- TMPL_VAR NAME="profile_name" -->" has not been created.</p><!-- /TMPL_IF -->
<!-- TMPL_IF EXPR="action eq 'edit'" --><p class="error">The CSV profile has not been modified.</p><!-- /TMPL_IF -->
<!-- TMPL_IF EXPR="action eq 'delete'" --><p class="error">The CSV profile has not been deleted.</p><!-- /TMPL_IF -->
<!-- /TMPL_IF -->
<!-- /TMPL_IF -->
<h1>New profile for CSV export</h1>
<form action="/cgi-bin/koha/tools/csv-profiles.pl" method="post">
<fieldset class="brief">
<label for="profile_name">Profile name :</label>
<input type="text" id="profile_name" name="profile_name" /><br /><br />
<label for="profile_description">Profile description :</label>
<textarea cols="50" name="profile_description" id="profile_description"></textarea><br /><br />
<label for="profile_content">Profile marcfields :</label>
<textarea cols="50" name="profile_content" id="profile_content"></textarea>
</fieldset>
<input type="hidden" name="action" value="create" />
<input type="submit" />
</form>
<!-- /TMPL_IF -->
<!-- TMPL_IF NAME="existing_profiles" -->
<br /><br />
<h1>Modify or delete an existing profile</h1>
<form action="/cgi-bin/koha/tools/csv-profiles.pl" method="post">
<fieldset class="brief">
<label for="modify_profile_name">Profile name :</label>
<select id="modify_profile_name" name="profile_name" onchange="javascript:reloadPage(this)">
<option value="0">-- Choose One --</option>
<!-- TMPL_LOOP NAME="existing_profiles" -->
<option value="<!-- TMPL_VAR NAME="export_format_id" -->"<!-- TMPL_IF EXPR="export_format_id eq selected_profile_id" --> selected="selected"<!-- /TMPL_IF-->><!-- TMPL_VAR NAME="profile" --></option>
<!-- /TMPL_LOOP -->
</select><br /><br />
<label for="modify_profile_description">Profile description :</label>
<textarea cols="50" name="profile_description" id="modify_profile_description"><!-- TMPL_VAR NAME="selected_profile_description" --></textarea><br /><br />
<label for="modify_profile_content">Profile marcfields :</label>
<textarea cols="50" name="profile_content" id="modify_profile_content"><!-- TMPL_VAR NAME="selected_profile_marcfields" --></textarea><br /><br />
<label for="delete">Delete selected profile ?</label>
<input type="checkbox" name="delete" id="delete" />
</fieldset>
<input type="hidden" name="modify_profile_id" value="<!-- TMPL_VAR NAME="selected_profile_id" -->" />
<input type="hidden" name="action" value="edit" />
<input type="submit" />
</form>
<!-- /TMPL_IF -->
</div>
</div>
<div class="yui-b">
</div>
</div>
<!-- TMPL_INCLUDE NAME="intranet-bottom.inc" -->

6
koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tmpl

@ -44,6 +44,12 @@
<dt><a href="/cgi-bin/koha/tags/review.pl">Tags</a></dt>
<dd>Moderate patron tags</dd>
<!-- /TMPL_IF -->
<!-- TMPL_IF NAME="CAN_user_tools_manage_csv_profiles" -->
<dt><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV Profiles</a></dt>
<dd>Manage CSV export profiles</dd>
<!-- /TMPL_IF -->
</dl>
</div>
<div class="yui-u">

4
koha-tmpl/opac-tmpl/prog/en/modules/opac-downloadcart.tmpl

@ -11,6 +11,10 @@
<option value="iso2709">iso2709</option>
<option value="ris">RIS</option>
<option value="bibtex">BibTex</option>
<!-- TMPL_LOOP NAME="csv_profiles" -->
<option value="<!-- TMPL_VAR NAME="export_format_id" -->">CSV - <!-- TMPL_VAR NAME="profile" --></option>
<!-- /TMPL_LOOP -->
</select>
<input type="hidden" name="bib_list" value="<!-- TMPL_VAR NAME="bib_list" -->" />
<input type="submit" name="save" value="Go" />

4
koha-tmpl/opac-tmpl/prog/en/modules/opac-downloadshelf.tmpl

@ -11,6 +11,10 @@
<option value="iso2709">iso2709</option>
<option value="ris">RIS</option>
<option value="bibtex">BibTex</option>
<!-- TMPL_LOOP NAME="csv_profiles" -->
<option value="<!-- TMPL_VAR NAME="export_format_id" -->">CSV - <!-- TMPL_VAR NAME="profile" --></option>
<!-- /TMPL_LOOP -->
</select>
<input type="hidden" name="shelfid" value="<!-- TMPL_VAR NAME="shelfid" -->" />
<input type="submit" name="save" value="Go" />

10
opac/opac-downloadcart.pl

@ -31,6 +31,7 @@ use C4::Output;
use C4::VirtualShelves;
use C4::Record;
use C4::Ris;
use C4::Csv;
use utf8;
use open qw( :std :utf8);
my $query = new CGI;
@ -57,6 +58,7 @@ if ($bib_list && $format) {
my $output;
# retrieve biblios from shelf
my $firstpass = 1;
foreach my $biblio (@bibs) {
my $record = GetMarcBiblio($biblio);
@ -65,9 +67,16 @@ if ($bib_list && $format) {
case "iso2709" { $output .= $record->as_usmarc(); }
case "ris" { $output .= marc2ris($record); }
case "bibtex" { $output .= marc2bibtex($record, $biblio); }
# We're in the case of a csv profile (firstpass is used for headers printing) :
case /^\d+$/ { $output .= marc2csv($record, $format, $firstpass); }
}
$firstpass = 0;
}
# If it was a CSV export we change the format after the export so the file extension is fine
$format = "csv" if ($format =~ m/^\d+$/);
print $query->header(
-type => 'application/octet-stream',
-'Content-Transfer-Encoding' => 'binary',
@ -75,6 +84,7 @@ if ($bib_list && $format) {
print $output;
} else {
$template->param(csv_profiles => GetCsvProfilesLoop());
$template->param(bib_list => $bib_list);
output_html_with_http_headers $query, $cookie, $template->output;
}

11
opac/opac-downloadshelf.pl

@ -31,6 +31,7 @@ use C4::Output;
use C4::VirtualShelves;
use C4::Record;
use C4::Ris;
use C4::Csv;
use utf8;
use open qw( :std :utf8);
my $query = new CGI;
@ -57,6 +58,7 @@ if ($shelfid && $format) {
my $output;
# retrieve biblios from shelf
my $firstpass = 1;
foreach my $biblio (@$items) {
my $biblionumber = $biblio->{biblionumber};
@ -66,16 +68,23 @@ if ($shelfid && $format) {
case "iso2709" { $output .= $record->as_usmarc(); }
case "ris" { $output .= marc2ris($record); }
case "bibtex" { $output .= marc2bibtex($record, $biblionumber); }
# We're in the case of a csv profile (firstpass is used for headers printing) :
case /^\d+$/ { $output .= marc2csv($record, $format, $firstpass); }
}
$firstpass = 0;
}
# If it was a CSV export we change the format after the export so the file extension is fine
$format = "csv" if ($format =~ m/^\d+$/);
print $query->header(
-type => 'application/octet-stream',
-'Content-Transfer-Encoding' => 'binary',
-attachment=>"shelf.$format");
print $output;
} else {
} else {
$template->param(csv_profiles => GetCsvProfilesLoop());
$template->param(shelfid => $shelfid);
output_html_with_http_headers $query, $cookie, $template->output;
}

121
tools/csv-profiles.pl

@ -0,0 +1,121 @@
#!/usr/bin/perl
# Copyright 2009 BibLibre
#
# This file is part of Koha.
#
# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
=head1 NAME
csv-profile.pl : Defines a CSV export profile
=head1 SYNOPSIS
=head1 DESCRIPTION
This script allow the user to define a new profile for CSV export
=head1 FUNCTIONS
=over 2
=cut
use strict;
use Data::Dumper;
use C4::Auth;
use C4::Context;
use C4::Output;
use CGI;
use C4::Koha;
use C4::Csv;
my $input = new CGI;
my $dbh = C4::Context->dbh;
# open template
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "tools/csv-profiles.tmpl",
query => $input,
type => "intranet",
authnotrequired => 0,
flagsrequired => { tools => 'manage_csv_profiles' },
debug => 1,
}
);
my $profile_name = $input->param("profile_name");
my $profile_description = $input->param("profile_description");
my $profile_content = $input->param("profile_content");
my $action = $input->param("action");
my $delete = $input->param("delete");
my $id = $input->param("id");
if ($delete) { $action = "delete"; }
if ($profile_name && $profile_content && $profile_description && $action) {
my $rows;
if ($action eq "create") {
my $query = "INSERT INTO export_format(export_format_id, profile, description, marcfields) VALUES (NULL, ?, ?, ?)";
my $sth = $dbh->prepare($query);
$rows = $sth->execute($profile_name, $profile_description, $profile_content);
}
if ($action eq "edit") {
my $query = "UPDATE export_format SET description=?, marcfields=? WHERE export_format_id=? LIMIT 1";
my $sth = $dbh->prepare($query);
$rows = $sth->execute($profile_description, $profile_content, $profile_name);
}
if ($action eq "delete") {
my $query = "DELETE FROM export_format WHERE export_format_id=? LIMIT 1";
my $sth = $dbh->prepare($query);
$rows = $sth->execute($profile_name);
}
$rows ? $template->param(success => 1) : $template->param(error => 1);
$template->param(profile_name => $profile_name);
$template->param(action => $action);
}
# If a profile has been selected for modification
if ($id) {
my $query = "SELECT export_format_id, profile, description, marcfields FROM export_format WHERE export_format_id = ?";
my $sth;
$sth = $dbh->prepare($query);
$sth->execute($id);
my $selected_profile = $sth->fetchrow_arrayref();
$template->param(
selected_profile_id => $selected_profile->[0],
selected_profile_name => $selected_profile->[1],
selected_profile_description => $selected_profile->[2],
selected_profile_marcfields => $selected_profile->[3]
);
}
# List of existing profiles
$template->param(existing_profiles => GetCsvProfilesLoop());
output_html_with_http_headers $input, $cookie, $template->output;
Loading…
Cancel
Save