@@ -, +, @@
---
C4/ImportExportFramework.pm | 986 ++++++++++++++++++++
admin/import_export_framework.pl | 68 ++
.../intranet-tmpl/prog/en/css/staff-global.css | 48 +
.../prog/en/modules/admin/biblio_framework.tmpl | 141 +++
4 files changed, 1243 insertions(+), 0 deletions(-)
create mode 100755 C4/ImportExportFramework.pm
create mode 100755 admin/import_export_framework.pl
mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl
--- a/C4/ImportExportFramework.pm
+++ a/C4/ImportExportFramework.pm
@@ -0,0 +1,986 @@
+package C4::ImportExportFramework;
+
+# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+use XML::LibXML;
+use XML::LibXML::XPathContext;
+use Digest::MD5 qw(md5_base64);
+use POSIX qw(strftime);
+
+use C4::Context;
+use C4::Debug;
+
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+BEGIN {
+ $VERSION = 3.03; # set version for version checking
+ require Exporter;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(
+ &ExportFramework
+ &ImportFramework
+ &createODS
+ );
+}
+
+
+use constant XMLSTR => '
+
+
+
+
+
+
+
+
+
+
+
+
+';
+
+
+use constant ODSSTR => '
+
+
+
+
+';
+
+
+use constant ODS_STYLES_STR => '
+
+
+
+
+
+';
+
+
+use constant ODS_SETTINGS_STR => '
+
+
+0
+0
+2000
+900
+
+View1
+
+01000020000
+
+
+Sheet1
+270
+0
+100
+50
+false
+true
+true
+true
+12632256
+true
+true
+true
+true
+false
+false
+true
+
+
+true
+true
+true
+12632256
+true
+3
+true
+true
+true
+false
+false
+true
+true
+Generic Printer
+true
+0
+false
+false
+true
+false
+
+';
+
+
+use constant ODS_MANIFEST_STR => '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+';
+
+
+=head1 NAME
+
+C4::ImportExportFramework - Import/Export Framework to Excel-xml/ODS Module Functions
+
+=head1 SYNOPSIS
+
+ use C4::ImportExportFramework;
+
+=head1 DESCRIPTION
+
+Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section
+
+Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section
+exporting the tables marc_tag_structure, marc_subfield_structure to excel-xml/ods or viceversa
+
+Functions for handling import/export.
+
+
+=head1 SUBROUTINES
+
+
+
+=head2 ExportFramework
+
+Export all the information of a Framework to an excel "xml" file or OpenDocument SpreadSheet "ods" file.
+
+return :
+succes
+
+=cut
+
+sub ExportFramework
+{
+ my ($frameworkcode, $xmlStrRef, $mode) = @_;
+
+ my $dbh = C4::Context->dbh;
+ if ($dbh) {
+ my $dom;
+ my $root;
+ my $elementSS;
+ eval {
+ my $parser = XML::LibXML->new();
+ $dom = $parser->parse_string(($mode && $mode eq 'ods')?ODSSTR:XMLSTR);
+ if ($dom) {
+ $root = $dom->documentElement();
+ if ($mode && $mode eq 'ods') {
+ my $elementBody = $dom->createElement('office:body');
+ $root->appendChild($elementBody);
+ $elementSS = $dom->createElement('office:spreadsheet');
+ $elementBody->appendChild($elementSS);
+ }
+ }
+ };
+ if ($@) {
+ $debug and warn "Error ExportFramework $@\n";
+ return 0;
+ }
+ if (_export_table('marc_tag_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) {
+ if (_export_table('marc_subfield_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) {
+ $$xmlStrRef = $dom->toString(1);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}#ExportFramework
+
+
+
+
+# Export all the data from a mysql table to an spreadsheet.
+sub _export_table
+{
+ my ($table, $dbh, $dom, $root, $frameworkcode, $mode) = @_;
+
+ if ($mode && $mode eq 'ods') {
+ _export_table_ods($table, $dbh, $dom, $root, $frameworkcode);
+ } else {
+ _export_table_excel($table, $dbh, $dom, $root, $frameworkcode);
+ }
+}
+
+
+# Export the mysql table to an ods file
+sub _export_table_ods
+{
+ my ($table, $dbh, $dom, $root, $frameworkcode) = @_;
+
+ eval {
+ my $elementTable = $dom->createElement('table:table');
+ $elementTable->setAttribute('table:name', $table);
+ $elementTable->setAttribute('table:print', 'false');
+ $root->appendChild($elementTable);
+ my $elementRow = $dom->createElement('table:table-row');
+ $elementTable->appendChild($elementRow);
+
+ my $elementCell;
+ my $elementData;
+ # First row with the name of the columns
+ my $query = 'SHOW COLUMNS FROM ' . $table;
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ my @fields = ();
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $elementCell = $dom->createElement('table:table-cell');
+ $elementCell->setAttribute('office:value-type', 'string');
+ $elementCell->setAttribute('office:value', $hashRef->{Field});
+ $elementRow->appendChild($elementCell);
+ $elementData = $dom->createElement('text:p');
+ $elementCell->appendChild($elementData);
+ $elementData->appendTextNode($hashRef->{Field});
+ push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'float':'string'};
+ }
+ # Populate rows with the data from mysql
+ $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?';
+ $sth = $dbh->prepare($query);
+ $sth->execute($frameworkcode);
+ my $data;
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $elementRow = $dom->createElement('table:table-row');
+ $elementTable->appendChild($elementRow);
+ for (@fields) {
+ $data = $hashRef->{$_->{name}};
+ if ($_->{type} eq 'float' && !defined($data)) {
+ $data = '0';
+ } elsif ($_->{type} eq 'string' && (!$data && $data ne '0')) {
+ $data = '#';
+ }
+ $data = _parseContent2Xml($data) if ($_->{type} eq 'string');
+ $elementCell = $dom->createElement('table:table-cell');
+ $elementCell->setAttribute('office:value-type', $_->{type});
+ $elementCell->setAttribute('office:value', $data);
+ $elementRow->appendChild($elementCell);
+ $elementData = $dom->createElement('text:p');
+ $elementCell->appendChild($elementData);
+ $elementData->appendTextNode($data);
+ }
+ }
+ };
+ if ($@) {
+ $debug and warn "Error _export_table_ods $@\n";
+ return 0;
+ }
+ return 1;
+}#_export_table_ods
+
+
+# Export the mysql table to an excel-xml (openoffice/libreoffice compatible) file
+sub _export_table_excel
+{
+ my ($table, $dbh, $dom, $root, $frameworkcode) = @_;
+
+ eval {
+ my $elementWS = $dom->createElement('Worksheet');
+ $elementWS->setAttribute('ss:Name', $table);
+ $root->appendChild($elementWS);
+ my $elementTable = $dom->createElement('ss:Table');
+ $elementWS->appendChild($elementTable);
+ my $elementRow = $dom->createElement('ss:Row');
+ $elementTable->appendChild($elementRow);
+
+ # First row with the name of the columns
+ my $elementCell;
+ my $elementData;
+ my $query = 'SHOW COLUMNS FROM ' . $table;
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ my @fields = ();
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $elementCell = $dom->createElement('ss:Cell');
+ $elementCell->setAttribute('ss:StyleID', 's27');
+ $elementRow->appendChild($elementCell);
+ $elementData = $dom->createElement('ss:Data');
+ $elementData->setAttribute('ss:Type', 'String');
+ $elementCell->appendChild($elementData);
+ $elementData->appendTextNode($hashRef->{Field});
+ push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'Number':'String'};
+ }
+ # Populate rows with the data from mysql
+ $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?';
+ $sth = $dbh->prepare($query);
+ $sth->execute($frameworkcode);
+ my $data;
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $elementRow = $dom->createElement('ss:Row');
+ $elementTable->appendChild($elementRow);
+ for (@fields) {
+ $elementCell = $dom->createElement('ss:Cell');
+ $elementRow->appendChild($elementCell);
+ $elementData = $dom->createElement('ss:Data');
+ $elementData->setAttribute('ss:Type', $_->{type});
+ $elementCell->appendChild($elementData);
+ $data = $hashRef->{$_->{name}};
+ if ($_->{type} eq 'Number' && !defined($data)) {
+ $data = '0';
+ } elsif ($_->{type} eq 'String' && (!$data && $data ne '0')) {
+ $data = '#';
+ }
+ $elementData->appendTextNode(($_->{type} eq 'String')?_parseContent2Xml($data):$data);
+ }
+ }
+ };
+ if ($@) {
+ $debug and warn "Error _export_table_excel $@\n";
+ return 0;
+ }
+ return 1;
+}#_export_table_excel
+
+
+
+
+
+
+
+# Format chars problematics to a correct format for xml.
+sub _parseContent2Xml
+{
+ my $content = shift;
+
+ $content =~ s/\&(?![a-zA-Z#0-9]{1,4};)/&/g;
+ $content =~ s/</g;
+ $content =~ s/>/>/g;
+ return $content;
+}#_parseContent2Xml
+
+
+# Get the tmp directory on the system
+sub _getTmp
+{
+ my $tmp = '/tmp';
+ if ($ENV{'TMP'} && -d $ENV{'TMP'}) {
+ $tmp = $ENV{'TMP'};
+ } elsif ($ENV{'TMPDIR'} && -d $ENV{'TMPDIR'}) {
+ $tmp = $ENV{'TMPDIR'};
+ } elsif ($ENV{'TEMP'} && -d $ENV{'TEMP'}) {
+ $tmp = $ENV{'TEMP'};
+ }
+ return $tmp;
+}#_getTmp
+
+
+# Create our tempdir directory for the ods process
+sub _createTmpDir
+{
+ my $tmp = shift;
+
+ my $tempdir = (-d $tmp)?$tmp . '/':'./';
+ $tempdir .= 'tmp_ods_' . Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$));
+ eval {
+ mkdir $tempdir;
+ };
+ if ($@) {
+ return undef;
+ } else {
+ return $tempdir;
+ }
+}#_createTmpDir
+
+=head2 createODS
+
+Creates a temporary directory to create the ods file and read it to store its content in a string.
+
+return :
+success
+
+=cut
+
+sub createODS
+{
+ my ($strContent, $lang, $strODSRef) = @_;
+
+ my $tmp = _getTmp();
+ my $tempModule = 1;
+ my $tempdir;
+ eval {
+ require File::Temp;
+ import File::Temp qw/ tempfile tempdir /;
+ $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 1);
+ };
+ if ($@) {
+ $tempModule = 0;
+ $tempdir = _createTmpDir($tmp);
+ }
+ if ($tempdir) {
+ # populate tempdir directory with the ods elements
+ eval {
+ if (open(OUT, "> $tempdir/content.xml")) {
+ print OUT $strContent;
+ close(OUT);
+ }
+ if (open(OUT, "> $tempdir/mimetype")) {
+ print OUT 'application/vnd.oasis.opendocument.spreadsheet';
+ close(OUT);
+ }
+ if (open(OUT, "> $tempdir/meta.xml")) {
+ print OUT _getMeta($lang);
+ close(OUT);
+ }
+ if (open(OUT, "> $tempdir/styles.xml")) {
+ print OUT ODS_STYLES_STR;
+ close(OUT);
+ }
+ if (open(OUT, "> $tempdir/settings.xml")) {
+ print OUT ODS_SETTINGS_STR;
+ close(OUT);
+ }
+ mkdir($tempdir.'/META-INF/');
+ mkdir($tempdir.'/Configurations2/');
+ mkdir($tempdir.'/Configurations2/acceleator/');
+ mkdir($tempdir.'/Configurations2/images/');
+ mkdir($tempdir.'/Configurations2/popupmenu/');
+ mkdir($tempdir.'/Configurations2/statusbar/');
+ mkdir($tempdir.'/Configurations2/floater/');
+ mkdir($tempdir.'/Configurations2/menubar/');
+ mkdir($tempdir.'/Configurations2/progressbar/');
+ mkdir($tempdir.'/Configurations2/toolbar/');
+ if (open(OUT, "> $tempdir/META-INF/manifest.xml")) {
+ print OUT ODS_MANIFEST_STR;
+ close(OUT);
+ }
+ };
+ if ($@) {
+ $debug and warn "Error createODS $@\n";
+ } else {
+ # create ods file from tempdir directory
+ eval {
+ require Archive::Zip;
+ import Archive::Zip qw( :ERROR_CODES :CONSTANTS );
+ my $zip = Archive::Zip->new();
+ $zip->addTree( $tempdir, '' );
+ $zip->writeToFileNamed('new.ods');
+ };
+ if ($@) {
+ system("cd $tempdir && zip -r new.ods ./");
+ }
+ my $ok = 0;
+ # read ods file and return as a string
+ if (-f "$tempdir/new.ods") {
+ if (open (MYFILE, "$tempdir/new.ods")) {
+ binmode MYFILE;
+ my $buffer;
+ while (read (MYFILE, $buffer, 65536)) {
+ $$strODSRef .= $buffer;
+ }
+ close(MYFILE);
+ $ok = 1;
+ }
+ }
+ # delete tempdir directory
+ if (!$tempModule && $tempdir) {
+ eval {
+ require File::Path;
+ import File::Temp qw/ rmtree /;
+ rmtree($tempdir);
+ };
+ if ($@) {
+ system("rm -rf $tempdir");
+ }
+ }
+ return 1 if ($ok);
+ }
+ }
+ return 0;
+}#createODS
+
+
+# return Meta content for ods file
+sub _getMeta
+{
+ my $lang = shift;
+
+ my $myDate = strftime ("%Y-%m-%dT%H:%M:%S", localtime(time()));
+ my $meta = '
+
+
+ ods-php
+ ' . $myDate . '
+ ' . $myDate . '
+ ' . $lang . '
+ 2
+ PT15S
+
+
+
+
+
+ ';
+ return $meta;
+}#_getMeta
+
+
+=head2 ImportFramework
+
+Import all the information of a Framework from a excel-xml/ods file.
+
+return :
+success
+
+=cut
+
+sub ImportFramework
+{
+ my ($filename, $frameworkcode, $deleteFilename) = @_;
+
+ my $tempdir;
+ my $ok = -1;
+ my $dbh = C4::Context->dbh;
+ if (-r $filename && $dbh) {
+ my $extension = '';
+ if ($filename =~ /\.(ods|xml)$/i) {
+ $extension = lc($1);
+ } else {
+ unlink ($filename) if ($deleteFilename);
+ return -1;
+ }
+ if ($extension eq 'ods') {
+ ($tempdir, $filename) = _openODS($filename, $deleteFilename);
+ }
+ if ($filename) {
+ eval {
+ my $parser = XML::LibXML->new();
+ my $dom = $parser->parse_file($filename);
+ if ($dom) {
+ my $element;
+ my $root = $dom->documentElement();
+ my $numDeleted = 0;
+ my $numDeletedAux = 0;
+ if (($numDeletedAux = _import_table($dbh, 'marc_tag_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield'], $extension)) >= 0) {
+ $numDeleted += $numDeletedAux if ($numDeletedAux > 0);
+ if (($numDeletedAux = _import_table($dbh, 'marc_subfield_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield', 'tagsubfield'], $extension)) >= 0) {
+ $numDeleted += $numDeletedAux if ($numDeletedAux > 0);
+ $ok = ($numDeleted > 0)?$numDeleted:0;
+ }
+ }
+ } else {
+ $debug and warn "Error ImportFramework couldn't create dom\n";
+ }
+ };
+ if ($@) {
+ $debug and warn "Error ImportFramework $@\n";
+ }
+ }
+ unlink ($filename) if ($deleteFilename);
+ } else {
+ $debug and warn "Error ImportFramework no conex to database or not readeable $filename\n";
+ }
+ if ($deleteFilename && $tempdir && -d $tempdir && -w $tempdir) {
+ eval {
+ require File::Path;
+ import File::Temp qw/ rmtree /;
+ rmtree($tempdir);
+ };
+ if ($@) {
+ system("rm -rf $tempdir");
+ }
+ }
+ return $ok;
+}#ImportFramework
+
+
+# Open (uncompress) ods file and return the content.xml file
+sub _openODS
+{
+ my ($filename, $deleteFilename) = @_;
+
+ my $tmp = _getTmp();
+ my $tempModule = 1;
+ my $tempdir;
+ eval {
+ require File::Temp;
+ import File::Temp qw/ tempfile tempdir /;
+ $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 0);
+ };
+ if ($@) {
+ $tempModule = 0;
+ $tempdir = _createTmpDir($tmp);
+ }
+ if ($tempdir) {
+ eval {
+ require Archive::Zip;
+ import Archive::Zip qw( :ERROR_CODES :CONSTANTS );
+ my $zip = Archive::Zip->new();
+ $zip->extractTree( $filename, $tempdir );
+ };
+ if ($@) {
+ system("unzip $filename -d $tempdir");
+ }
+ if (-f "$tempdir/content.xml") {
+ unlink ($filename) if ($deleteFilename);
+ return ($tempdir, "$tempdir/content.xml");
+ }
+ }
+ unlink ($filename) if ($deleteFilename);
+ return ($tempdir, undef);
+}#_openODS
+
+
+
+# Check the table and columns corresponds with worksheet
+sub _check_validity_worksheet
+{
+ my ($dbh, $table, $nodeFields, $fieldsA, $format) = @_;
+
+ my $ret = 0;
+ eval {
+ my $query = 'DESCRIBE ' . $table;
+ my $sth = $dbh->prepare($query);
+ $sth->execute();
+ $sth->finish;
+ $query = 'SHOW COLUMNS FROM ' . $table;
+ $sth = $dbh->prepare($query);
+ $sth->execute();
+ my $fields = {};
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $fields->{$hashRef->{Field}} = $hashRef->{Field};
+ }
+ my @fields;
+ my $fieldsR;
+ if ($fieldsA) {
+ $fieldsR = $fieldsA;
+ } else {
+ $fieldsR = \@fields;
+ _getFields($nodeFields, $fieldsR, $format);
+ }
+ $ret = 1;
+ for (@$fieldsR) {
+ unless (exists($fields->{$_})) {
+ $ret = 0;
+ last;
+ }
+ }
+ };
+ return $ret;
+}#_check_validity_worksheet
+
+
+# Import the data from an excel-xml/ods to mysql tables.
+sub _import_table
+{
+ my ($dbh, $table, $frameworkcode, $dom, $PKArray, $format) = @_;
+ my %fields2Delete;
+ my $query;
+ eval {
+ my @fields = @$PKArray;
+ shift @fields;
+ $query = 'SELECT ' . join(',', @fields) . ' FROM ' . $table . ' WHERE frameworkcode=?';
+ my $sth = $dbh->prepare($query);
+ $sth->execute($frameworkcode);
+ my $field;
+ while (my $hashRef = $sth->fetchrow_hashref) {
+ $field = '';
+ map { $field .= $hashRef->{$_} . '_'; } @fields;
+ chop $field;
+ $fields2Delete{$field} = 1;
+ }
+ $sth->finish;
+ };
+ my $ok = 0;
+ if ($format && $format eq 'ods') {
+ $ok = _import_table_ods($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete);
+ } else {
+ $ok = _import_table_excel($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete);
+ }
+ if ($ok) {
+ if (($ok = scalar(keys %fields2Delete)) > 0) {
+ $query = 'DELETE FROM ' . $table . ' WHERE ';
+ map {$query .= $_ . '=? AND ';} @$PKArray;
+ $query = substr($query, 0, -4);
+ my $sth = $dbh->prepare($query);
+ for (keys %fields2Delete) {
+ eval {
+ $sth->execute(($frameworkcode, split('_', $_)));
+ };
+ }
+ }
+ } else {
+ $ok = -1;
+ }
+ return $ok;
+}#_import_table
+
+
+# Process the rows of a worksheet and insert/update them in a mysql table.
+sub _processRows_Table
+{
+ my ($dbh, $frameworkcode, $nodeR, $table, $PKArray, $format, $fields2Delete) = @_;
+
+ my $query;
+ my @fields = ();
+ my $fields = '';
+ my $dataStr = '';
+ my $updateStr = '';
+ my $j = 0;
+ my $db_scheme = C4::Context->config("db_scheme");
+ my $ok = 0;
+ my @fieldsPK = @$PKArray;
+ shift @fieldsPK;
+ while ($nodeR) {
+ if ($nodeR->nodeType == 1 && (($format && $format eq 'ods' && $nodeR->nodeName =~ /(?:table:)?table-row/) || ($nodeR->nodeName =~ /(?:ss:)?Row/)) && $nodeR->hasChildNodes()) {
+ if ($j == 0) {
+ # Get name columns
+ _getFields($nodeR, \@fields, $format);
+ return 0 unless _check_validity_worksheet($dbh, $table, $nodeR, \@fields, $format);
+ $fields = join(',', @fields);
+ $dataStr = '';
+ map { $dataStr .= '?,';} @fields;
+ chop($dataStr) if ($dataStr);
+ $updateStr = '';
+ map { $updateStr .= $_ . '=?,';} @fields;
+ chop($updateStr) if ($updateStr);
+ } else {
+ # Get data from row
+ my ($dataFields, $dataFieldsR) = _getDataFields($frameworkcode, $nodeR, \@fields, $format);
+ if (scalar(@fields) == scalar(@$dataFieldsR)) {
+ if ($db_scheme eq 'mysql') {
+ $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ') ON DUPLICATE KEY UPDATE ' . $updateStr;
+ } else {
+ $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ')';
+ }
+ eval {
+ my $sth = $dbh->prepare($query);
+ if ($db_scheme eq 'mysql') {
+ $sth->execute((@$dataFieldsR, @$dataFieldsR));
+ } else {
+ $sth->execute(@$dataFieldsR);
+ }
+ };
+ if ($@) {
+ unless ($db_scheme eq 'mysql') {
+ $query = 'UPDATE ' . $table . ' SET ' . $updateStr . ' WHERE ';
+ map {$query .= $_ . '=? AND ';} @$PKArray;
+ $query = substr($query, 0, -4);
+ eval {
+ my $sth2 = $dbh->prepare($query);
+ my @dataPK = ();
+ map {push @dataPK, $dataFields->{$_};} @$PKArray;
+ $sth2->execute((@$dataFieldsR, @dataPK));
+ };
+ $ok = 1 unless ($@);
+ }
+ $debug and warn "Error _processRows_Table $@\n";
+ } else {
+ $ok = 1;
+ }
+ if ($ok) {
+ my $field = '';
+ map { $field .= $dataFields->{$_} . '_'; } @fieldsPK;
+ chop $field;
+ delete $fields2Delete->{$field} if (exists($fields2Delete->{$field}));
+ }
+ $ok = 0;
+ }
+ }
+ $j++;
+ }
+ $nodeR = $nodeR->nextSibling;
+ }
+ return 1;
+}#_processRows_Table
+
+
+# Import worksheet from the ods content.xml file to the mysql table
+sub _import_table_ods
+{
+ my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_;
+
+ my $xc = XML::LibXML::XPathContext->new($dom);
+ $xc->registerNs('xmlns:office','urn:oasis:names:tc:opendocument:xmlns:office:1.0');
+ $xc->registerNs('xmlns:table','urn:oasis:names:tc:opendocument:xmlns:table:1.0');
+ $xc->registerNs('xmlns:text','urn:oasis:names:tc:opendocument:xmlns:text:1.0');
+ my @nodes;
+ @nodes = $xc->findnodes('//table:table[@table:name="' . $table . '"]');
+ if (@nodes == 1 && $nodes[0]->hasChildNodes()) {
+ my $nodeR = $nodes[0]->firstChild;
+ return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, 'ods', $fields2Delete);
+ } else {
+ $debug and warn "Error _import_table_ods there's not worksheet for $table\n";
+ }
+ return 0;
+}#_import_table_ods
+
+
+# Import worksheet from the excel-xml file to the mysql table
+sub _import_table_excel
+{
+ my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_;
+
+ my $xc = XML::LibXML::XPathContext->new($dom);
+ $xc->registerNs('xmlns','urn:schemas-microsoft-com:office:spreadsheet');
+ $xc->registerNs('xmlns:ss','urn:schemas-microsoft-com:office:spreadsheet');
+ $xc->registerNs('xmlns:x','urn:schemas-microsoft-com:office:excel');
+ my @nodes;
+ @nodes = $xc->findnodes('//ss:Worksheet[@ss:Name="' . $table . '"]');
+ if (@nodes > 0) {
+ for (my $i=0; $i < @nodes; $i++) {
+ my @nodesT = $nodes[$i]->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Table');
+ if (@nodesT == 1 && $nodesT[0]->hasChildNodes()) {
+ my $nodeR = $nodesT[0]->firstChild;
+ return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, undef, $fields2Delete);
+ }
+ }
+ } else {
+ $debug and warn "Error _import_table_excel there's not worksheet for $table\n";
+ }
+ return 0;
+}#_import_table_excel
+
+
+# Get the data from a cell on a ods file through the value attribute or the text node
+sub _getDataNodeODS
+{
+ my $node = shift;
+
+ my $data;
+ my $repeated = 0;
+ if ($node->nodeType == 1 && $node->nodeName =~ /(?:table:)?table-cell/) {
+ if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value')) {
+ $data = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value');
+ } elsif ($node->hasChildNodes()) {
+ my @nodes2 = $node->getElementsByTagNameNS('urn:oasis:names:tc:opendocument:xmlns:text:1.0', 'p');
+ if (@nodes2 == 1 && $nodes2[0]->hasChildNodes()) {
+ $data = $nodes2[0]->firstChild->nodeValue;
+ }
+ }
+ if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated')) {
+ $repeated = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated');
+ }
+ }
+ return ($data, $repeated);
+}#_getDataNodeODS
+
+
+# Get the data from a row of a spreadsheet
+sub _getDataFields
+{
+ my ($frameworkcode, $node, $fields, $format) = @_;
+
+ my $dataFields = {};
+ my @dataFieldsA = ();
+ if ($node && $node->hasChildNodes()) {
+ my $node2 = $node->firstChild;
+ my ($data, $repeated);
+ my $i = 0;
+ my $ok = 0;
+ $repeated = 0;
+ while ($node2) {
+ if ($format && $format eq 'ods') {
+ ($data, $repeated) = _getDataNodeODS($node2) if ($repeated <= 0);
+ $repeated--;
+ $ok = 1 if (defined($data));
+ } else {
+ if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) {
+ my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data');
+ if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) {
+ $data = $nodes3[0]->firstChild->nodeValue;
+ $ok = 1;
+ }
+ }
+ }
+ if ($ok) {
+ $data = '' if ($data eq '#');
+ $data = $frameworkcode if ($fields->[$i] eq 'frameworkcode');
+ $dataFields->{$fields->[$i]} = $data;
+ push @dataFieldsA, $data;
+ $i++;
+ }
+ $ok = 0;
+ $node2 = $node2->nextSibling if ($repeated <= 0);
+ }
+ }
+ return ($dataFields, \@dataFieldsA);
+}#_getDataFields
+
+
+# Get the data from the first row to know the column names
+sub _getFields
+{
+ my ($node, $fields, $format) = @_;
+
+ if ($node && $node->hasChildNodes()) {
+ my $node2 = $node->firstChild;
+ my ($data, $repeated);
+ while ($node2) {
+ if ($format && $format eq 'ods') {
+ ($data, $repeated) = _getDataNodeODS($node2);
+ push @$fields, $data if (defined($data));
+ } else {
+ if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) {
+ my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data');
+ if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) {
+ $data = $nodes3[0]->firstChild->nodeValue;
+ push @$fields, $data;
+ }
+ }
+ }
+ $node2 = $node2->nextSibling;
+ }
+ }
+}#_getFields
+
+
+
+
+1;
+__END__
+
+=head1 AUTHOR
+
+Koha Development Team
+
+=cut
+
+
--- a/admin/import_export_framework.pl
+++ a/admin/import_export_framework.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl
+
+# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura
+#
+# 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+use strict;
+use warnings;
+use CGI;
+use C4::Context;
+use C4::ImportExportFramework;
+
+my $input = new CGI;
+
+my $frameworkcode = $input->param('frameworkcode') || '';
+my $action = $input->param('action') || 'export';
+
+## Exporting
+if ($action eq 'export' && $input->request_method() eq 'GET') {
+ my $strXml = '';
+ ExportFramework($frameworkcode, \$strXml, $input->param('type_export_' . $frameworkcode));
+ if ($input->param('type_export_' . $frameworkcode) eq 'excel') {
+ # Excel-xml file
+ print $input->header(-type => 'application/excel', -attachment => 'export_' . $frameworkcode . '.xml');
+ print $strXml;
+ } else {
+ # ODS file
+ my $strODS = '';
+ createODS($strXml, 'en', \$strODS);
+ print $input->header(-type => 'application/vnd.oasis.opendocument.spreadsheet', -attachment => 'export_' . $frameworkcode . '.ods');
+ print $strODS;
+ }
+## Importing
+} elsif ($input->request_method() eq 'POST') {
+ my $ok = -1;
+ my $fieldname = 'file_import_' . $frameworkcode;
+ my $filename = $input->param($fieldname);
+ # upload the input file
+ if ($filename && $filename =~ /\.(ods|xml)$/i) {
+ my $extension = $1;
+ my $uploadFd = $input->upload($fieldname);
+ if ($uploadFd && !$input->cgi_error) {
+ my $tmpfilename = $input->tmpFileName($input->param($fieldname));
+ $filename = $tmpfilename . '.' . $extension; # rename the tmp file with the extension
+ $ok = ImportFramework($filename, $frameworkcode, 1) if (rename($tmpfilename, $filename));
+ }
+ }
+ if ($ok >= 0) { # If everything went ok go to the framework marc structure
+ print $input->redirect( -location => '/cgi-bin/koha/admin/marctagstructure.pl?frameworkcode=' . $frameworkcode);
+ } else {
+ # If something failed go to the list of frameworks and show message
+ print $input->redirect( -location => '/cgi-bin/koha/admin/biblio_framework.pl?error_import_export=' . $frameworkcode);
+ }
+}
--- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
+++ a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
@@ -1924,3 +1924,51 @@ ul.budget_hierarchy li:first-child:after {
margin : 1em 0;
}
fieldset.rows+h3 {clear:both;padding-top:.5em;}
+
+.import_export{
+ position:relative;
+}
+.import_export .import_export_options{
+ background: white;
+ border: 1px solid #CDCDCD;
+ left: 60px;
+ padding: 10px;
+ position: absolute;
+ top: 0;
+ z-index: 1;
+ width: 300px;
+}
+.import_export_options li{
+ display: block;
+ list-style: none;
+ padding-top: 10px;
+}
+.import_export_options .import_export_close {
+ cursor: pointer;
+ text-decoration: underline;
+}
+.import_export_options .export_ok {
+ padding: 10;
+ background: #E3E3E3 none;
+ cursor: pointer;
+ margin-left: 20px;
+ border: none;
+}
+.import_export_options .import_ok {
+ padding: 10;
+ background: #E3E3E3 none;
+ cursor: pointer;
+ margin-left: 20px;
+ border: none;
+}
+.form_import .input_import {
+ border: 1px solid #bcbcbc;
+}
+.import_export_options .importing {
+ padding: inherit;
+ background: none;
+}
+.li_close_import_export {
+ text-align: right;
+}
+
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl
@@ -48,6 +48,88 @@ $(document).ready(function() {
});
//]]>
+
+
@@ -115,6 +197,8 @@ $(document).ready(function() {
|
Edit |
Delete |
+ Export |
+ Import |
|
@@ -122,6 +206,34 @@ $(document).ready(function() {
">MARC structure |
|
|
+
+ |
+
+ |
@@ -133,6 +245,35 @@ $(document).ready(function() {
" >MARC structure |
?op=add_form&frameworkcode=">Edit |
?op=delete_confirm&frameworkcode=">Delete |
+
+
+ |
+
+ |
--