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

(-)a/C4/Circulation.pm (-2 / +15 lines)
Lines 3328-3336 sub GetOfflineOperation { Link Here
3328
}
3328
}
3329
3329
3330
sub AddOfflineOperation {
3330
sub AddOfflineOperation {
3331
    my ( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount ) = @_;
3331
    my $dbh = C4::Context->dbh;
3332
    my $dbh = C4::Context->dbh;
3332
    my $sth = $dbh->prepare("INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber) VALUES(?,?,?,?,?,?)");
3333
    my $sth = $dbh->prepare("INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber, amount) VALUES(?,?,?,?,?,?,?)");
3333
    $sth->execute( @_ );
3334
    $sth->execute( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount );
3334
    return "Added.";
3335
    return "Added.";
3335
}
3336
}
3336
3337
Lines 3349-3354 sub ProcessOfflineOperation { Link Here
3349
        $report = ProcessOfflineReturn( $operation );
3350
        $report = ProcessOfflineReturn( $operation );
3350
    } elsif ( $operation->{action} eq 'issue' ) {
3351
    } elsif ( $operation->{action} eq 'issue' ) {
3351
        $report = ProcessOfflineIssue( $operation );
3352
        $report = ProcessOfflineIssue( $operation );
3353
    } elsif ( $operation->{action} eq 'payment' ) {
3354
        $report = ProcessOfflinePayment( $operation );
3352
    }
3355
    }
3353
3356
3354
    DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid};
3357
    DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid};
Lines 3418-3423 sub ProcessOfflineIssue { Link Here
3418
    }
3421
    }
3419
}
3422
}
3420
3423
3424
sub ProcessOfflinePayment {
3425
    my $operation = shift;
3426
3427
    my $borrower = C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ); # Get borrower from operation cardnumber
3428
    my $amount = $operation->{amount};
3429
3430
    recordpayment( $borrower->{borrowernumber}, $amount );
3431
3432
    return "Success."
3433
}
3421
3434
3422
3435
3423
=head2 TransferSlip
3436
=head2 TransferSlip
(-)a/installer/data/mysql/kohastructure.sql (-9 / +9 lines)
Lines 1573-1589 CREATE TABLE `patronimage` ( -- information related to patron images Link Here
1573
-- so MyISAM is better in this case
1573
-- so MyISAM is better in this case
1574
1574
1575
DROP TABLE IF EXISTS `pending_offline_operations`;
1575
DROP TABLE IF EXISTS `pending_offline_operations`;
1576
CREATE TABLE `pending_offline_operations` (
1576
CREATE TABLE pending_offline_operations (
1577
  `operationid` int(11) NOT NULL AUTO_INCREMENT,
1577
  operationid int(11) NOT NULL AUTO_INCREMENT,
1578
  `userid` varchar(30) NOT NULL,
1578
  userid varchar(30) NOT NULL,
1579
  `branchcode` varchar(10) NOT NULL,
1579
  branchcode varchar(10) NOT NULL,
1580
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
1580
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
1581
  `action` varchar(10) NOT NULL,
1581
  `action` varchar(10) NOT NULL,
1582
  `barcode` varchar(20) NOT NULL,
1582
  barcode varchar(20) DEFAULT NULL,
1583
  `cardnumber` varchar(16) DEFAULT NULL,
1583
  cardnumber varchar(16) DEFAULT NULL,
1584
  PRIMARY KEY (`operationid`)
1584
  amount decimal(28,6) DEFAULT NULL,
1585
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
1585
  PRIMARY KEY (operationid)
1586
1586
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
1587
1587
1588
1588
1589
--
1589
--
(-)a/installer/data/mysql/updatedatabase.pl (-2 / +9 lines)
Lines 5828-5835 if(C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
5828
    SetVersion($DBversion);
5828
    SetVersion($DBversion);
5829
}
5829
}
5830
5830
5831
5832
5833
$DBversion = "3.09.00.050";
5831
$DBversion = "3.09.00.050";
5834
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
5832
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
5835
    $dbh->do("ALTER TABLE authorised_values MODIFY category varchar(16) NOT NULL DEFAULT '';");
5833
    $dbh->do("ALTER TABLE authorised_values MODIFY category varchar(16) NOT NULL DEFAULT '';");
Lines 6505-6510 if ( CheckVersion($DBversion) ) { Link Here
6505
    SetVersion($DBversion);
6503
    SetVersion($DBversion);
6506
}
6504
}
6507
6505
6506
6507
$DBversion = "3.11.00.XXX";
6508
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
6509
    $dbh->do("ALTER TABLE `pending_offline_operations` CHANGE `barcode` `barcode` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
6510
    $dbh->do("ALTER TABLE `pending_offline_operations` ADD `amount` DECIMAL( 28, 6 ) NULL DEFAULT NULL");
6511
    print "Upgrade to $DBversion done (Bug 8220 - Allow koc uploads to go to process queue)\n";
6512
    SetVersion ($DBversion);
6513
}
6514
6508
=head1 FUNCTIONS
6515
=head1 FUNCTIONS
6509
6516
6510
=head2 TableExists($table)
6517
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt (-2 / +6 lines)
Lines 53-60 Link Here
53
	<div class="yui-u">
53
	<div class="yui-u">
54
        <h5>Offline circulation</h5>
54
        <h5>Offline circulation</h5>
55
		<ul>
55
		<ul>
56
            <li><a href="/cgi-bin/koha/offline_circ/process_koc.pl">Offline circulation file (.koc) uploader</a></li>
56
                    <li><a href="/cgi-bin/koha/offline_circ/process_koc.pl">Upload offline circulation file (.koc)</a></li>
57
            <li><a href="/cgi-bin/koha/offline_circ/list.pl">Offline circulation</a> (<a href="https://addons.mozilla.org/[% lang %]/firefox/addon/koct/">Firefox add-on</a>)</li>
57
                    <li><a href="/cgi-bin/koha/offline_circ/list.pl">Pending offline circulation actions</a>
58
                    <ul>
59
                        <li><a href="http://kylehall.info/index.php/projects/koha/koha-offline-circulation/">Get desktop application</a></li>
60
                        <li><a href="https://addons.mozilla.org/[% lang %]/firefox/addon/koct/">Get Firefox add-on</a></li>
61
                    </ul>
58
		</ul>
62
		</ul>
59
	</div>
63
	</div>
60
</div>
64
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/offline_circ/enqueue_koc.tt (+31 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Circulation &rsaquo; Add offline circulations to queue</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
</head>
5
<body>
6
[% INCLUDE 'header.inc' %]
7
[% INCLUDE 'circ-search.inc' %]
8
9
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> &rsaquo; <a href="/cgi-bin/koha/offline_circ/process_koc.pl">Add offline circulations to queue</a></div>
10
11
<div id="doc" class="yui-t7">
12
13
   <div id="bd">
14
15
  <h2>Koha offline circulation</h2>
16
  <p>Your file was processed.</p>
17
18
[% FOREACH message IN messages %]
19
  [% IF ( message.message ) %]
20
      [% IF ( message.ERROR_file_version ) %]
21
          <div class="dialog alert"><p>Warning: This file is version [% message.upload_version %], but I only know how to import version [% message.current_version %]. I'll try my best.</p>
22
      [% END %]
23
  [% END %]
24
[% END %]
25
26
<p><a href="process_koc.pl">Upload another KOC file</a></p>
27
28
<p><a href="list.pl">View pending offline circulation actions</a></p>
29
30
</div>
31
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/offline_circ/list.tt (-2 / +4 lines)
Lines 78-84 Link Here
78
			            <th>Date</th>
78
			            <th>Date</th>
79
			            <th>Action</th>
79
			            <th>Action</th>
80
			            <th>Barcode</th>
80
			            <th>Barcode</th>
81
                        <th>Card number</th>
81
                                    <th>Card number</th>
82
                                    <th>Amount</th>
82
		            </tr>
83
		            </tr>
83
		        </thead>
84
		        </thead>
84
		        <tbody>
85
		        <tbody>
Lines 95-101 Link Here
95
			                    [% END %]
96
			                    [% END %]
96
			                </td>
97
			                </td>
97
			                <td>
98
			                <td>
98
			                [% IF ( operation.actionissue ) %]
99
			                [% IF ( operation.actionissue || operation.actionpayment) %]
99
		                        [% IF ( operation.borrowernumber ) %]
100
		                        [% IF ( operation.borrowernumber ) %]
100
		                            <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% operation.borrowernumber %]" title="[% operation.borrower %]">[% operation.cardnumber %]</a>
101
		                            <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% operation.borrowernumber %]" title="[% operation.borrower %]">[% operation.cardnumber %]</a>
101
		                        [% ELSE %]
102
		                        [% ELSE %]
Lines 103-108 Link Here
103
		                        [% END %]
104
		                        [% END %]
104
			                [% END %]
105
			                [% END %]
105
			                </td>
106
			                </td>
107
                                        <td>[% operation.amount %]</td>
106
		                </tr>
108
		                </tr>
107
		            [% END %]
109
		            [% END %]
108
		        </tbody>
110
		        </tbody>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/offline_circ/process_koc.tt (-12 / +22 lines)
Lines 6-27 Link Here
6
<script type="text/javascript">
6
<script type="text/javascript">
7
//<![CDATA[
7
//<![CDATA[
8
$(document).ready(function(){
8
$(document).ready(function(){
9
	$("#processfile").hide();
9
    $("#enqueuefile").hide();
10
    $("#processfile").hide();
10
});
11
});
12
11
function CheckUpload(f){
13
function CheckUpload(f){
12
	if(f.fileToUpload.value == ""){
14
    if (f.fileToUpload.value == ""){
13
		alert(_("Please choose a file to upload"));
15
        alert(_("Please choose a file to upload"));
14
	} else {
16
    } else {
15
		return ajaxFileUpload()
17
        return ajaxFileUpload()
16
	}
18
    }
17
		return false;
19
    return false;
18
}
20
}
21
19
function CheckForm(f) {
22
function CheckForm(f) {
20
    if (f.uploadedfileid.value == '') {
23
    if (f.uploadedfileid.value == '') {
21
        alert(_("Please upload a file first."));
24
        alert(_("Please upload a file first."));
22
    } else {
25
    } else {
23
		$("#fileuploadstatus").hide();
26
        $("#fileuploadstatus").hide();
24
		$("#fileuploadform").slideUp();
27
        $("#fileuploadform").slideUp();
25
        return submitBackgroundJob(f);
28
        return submitBackgroundJob(f);
26
    }
29
    }
27
    return false;
30
    return false;
Lines 60-66 function CheckForm(f) { Link Here
60
	[% IF ( message.payment ) %]<p>Accepted payment ([% message.amount %]) from <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% message.borrowernumber %]">[% message.firstname %] [% message.surname %]</a> ([% message.cardnumber %]): [% message.datetime %]</p>[% END %]
63
	[% IF ( message.payment ) %]<p>Accepted payment ([% message.amount %]) from <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% message.borrowernumber %]">[% message.firstname %] [% message.surname %]</a> ([% message.cardnumber %]): [% message.datetime %]</p>[% END %]
61
  [% END %]
64
  [% END %]
62
[% ELSE %]
65
[% ELSE %]
63
  <h2>Upload offline circulation data</h2>
66
   <h2>Upload offline circulation data</h2>
67
64
   <div id="fileuploadform">
68
   <div id="fileuploadform">
65
     <form method="post" action="[% SCRIPT_NAME %]" enctype="multipart/form-data">
69
     <form method="post" action="[% SCRIPT_NAME %]" enctype="multipart/form-data">
66
		<fieldset class="brief">
70
		<fieldset class="brief">
Lines 72-82 function CheckForm(f) { Link Here
72
     <div id="fileuploadstatus" style="display:none">Upload progress: <div id="fileuploadprogress"></div> <span id="fileuploadpercent">0</span>%</div>
76
     <div id="fileuploadstatus" style="display:none">Upload progress: <div id="fileuploadprogress"></div> <span id="fileuploadpercent">0</span>%</div>
73
     <div id="fileuploadfailed" style="display:none"></div>
77
     <div id="fileuploadfailed" style="display:none"></div>
74
   </div>
78
   </div>
75
   <form action="process_koc.pl" id="processfile" method="post" enctype="multipart/form-data">
79
80
   <form action="enqueue_koc.pl" id="processfile" method="post" enctype="multipart/form-data">
81
     <input type="hidden" name="uploadedfileid" id="uploadedfileid" value="" />
82
     <input type="submit" value="Add to offline circulation queue" onclick="return CheckForm(this.form);" id="queueformsubmit" />
83
   </form>
84
85
   <form action="process_koc.pl" id="enqueuefile" method="post" enctype="multipart/form-data">
76
     <input type="hidden" name="uploadedfileid" id="uploadedfileid" value="" />
86
     <input type="hidden" name="uploadedfileid" id="uploadedfileid" value="" />
77
     <input type="hidden" name="runinbackground" id="runinbackground" value="" />
87
     <input type="hidden" name="runinbackground" id="runinbackground" value="" />
78
     <input type="hidden" name="completedJobID" id="completedJobID" value="" />
88
     <input type="hidden" name="completedJobID" id="completedJobID" value="" />
79
     <input type="submit" value="Process offline circulation file" onclick="return CheckForm(this.form);" id="mainformsubmit" />
89
     <input type="submit" value="Apply directly" onclick="return CheckForm(this.form);" id="mainformsubmit" />
80
     <div id="jobstatus" style="display:none">Job progress: <div id="jobprogress"></div> <span id="jobprogresspercent">0</span>%</div>
90
     <div id="jobstatus" style="display:none">Job progress: <div id="jobprogress"></div> <span id="jobprogresspercent">0</span>%</div>
81
     <div id="jobfailed" style="display:none"></div>
91
     <div id="jobfailed" style="display:none"></div>
82
   </form>
92
   </form>
(-)a/offline_circ/enqueue_koc.pl (+197 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# 2008 Kyle Hall <kyle.m.hall@gmail.com>
4
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
#
20
21
use strict;
22
use warnings;
23
24
use CGI;
25
use C4::Output;
26
use C4::Auth;
27
use C4::Koha;
28
use C4::Context;
29
use C4::Biblio;
30
use C4::Accounts;
31
use C4::Circulation;
32
use C4::Items;
33
use C4::Members;
34
use C4::Stats;
35
use C4::UploadedFile;
36
37
use Date::Calc qw( Add_Delta_Days Date_to_Days );
38
39
use constant DEBUG => 0;
40
41
# this is the file version number that we're coded against.
42
my $FILE_VERSION = '1.0';
43
44
my $query = CGI->new;
45
my @output;
46
47
my ($template, $loggedinuser, $cookie) = get_template_and_user({
48
    template_name => "offline_circ/enqueue_koc.tmpl",
49
    query => $query,
50
    type => "intranet",
51
    authnotrequired => 0,
52
     flagsrequired   => { circulate => "circulate_remaining_permissions" },
53
});
54
55
56
my $fileID=$query->param('uploadedfileid');
57
my %cookies = parse CGI::Cookie($cookie);
58
my $sessionID = $cookies{'CGISESSID'}->value;
59
## 'Local' globals.
60
our $dbh = C4::Context->dbh();
61
62
if ($fileID) {
63
    my $uploaded_file = C4::UploadedFile->fetch($sessionID, $fileID);
64
    my $fh = $uploaded_file->fh();
65
    my @input_lines = <$fh>;
66
67
    my $header_line = shift @input_lines;
68
    my $file_info   = parse_header_line($header_line);
69
    if ($file_info->{'Version'} ne $FILE_VERSION) {
70
        push @output, {
71
            message => 1,
72
            ERROR_file_version => 1,
73
            upload_version => $file_info->{'Version'},
74
            current_version => $FILE_VERSION
75
        };
76
    }
77
78
    my $userid = C4::Context->userenv->{id};
79
    my $branchcode = C4::Context->userenv->{branch};
80
81
    foreach  my $line (@input_lines)  {
82
        my $command_line = parse_command_line($line);
83
        my $timestamp = $command_line->{'date'} . ' ' . $command_line->{'time'};
84
        my $action = $command_line->{'command'};
85
        my $barcode = $command_line->{'barcode'};
86
        my $cardnumber = $command_line->{'cardnumber'};
87
        my $amount = $command_line->{'amount'};
88
89
        AddOfflineOperation( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount );
90
    }
91
92
}
93
94
$template->param( messages => \@output );
95
96
output_html_with_http_headers $query, $cookie, $template->output;
97
98
=head1 FUNCTIONS
99
100
=head2 parse_header_line
101
102
parses the header line from a .koc file. This is the line that
103
specifies things such as the file version, and the name and version of
104
the offline circulation tool that generated the file. See
105
L<http://wiki.koha-community.org/wiki/Koha_offline_circulation_file_format>
106
for more information.
107
108
pass in a string containing the header line (the first line from th
109
file).
110
111
returns a hashref containing the information from the header.
112
113
=cut
114
115
sub parse_header_line {
116
    my $header_line = shift;
117
    chomp($header_line);
118
    $header_line =~ s/\r//g;
119
120
    my @fields = split( /\t/, $header_line );
121
    my %header_info = map { split( /=/, $_ ) } @fields;
122
    return \%header_info;
123
}
124
125
=head2 parse_command_line
126
127
=cut
128
129
sub parse_command_line {
130
    my $command_line = shift;
131
    chomp($command_line);
132
    $command_line =~ s/\r//g;
133
134
    my ( $timestamp, $command, @args ) = split( /\t/, $command_line );
135
    my ( $date,      $time,    $id )   = split( /\s/, $timestamp );
136
137
    my %command = (
138
        date    => $date,
139
        time    => $time,
140
        id      => $id,
141
        command => $command,
142
    );
143
144
    # set the rest of the keys using a hash slice
145
    my $argument_names = arguments_for_command($command);
146
    @command{@$argument_names} = @args;
147
148
    return \%command;
149
150
}
151
152
=head2 arguments_for_command
153
154
fetches the names of the columns (and function arguments) found in the
155
.koc file for a particular command name. For instance, the C<issue>
156
command requires a C<cardnumber> and C<barcode>. In that case this
157
function returns a reference to the list C<qw( cardnumber barcode )>.
158
159
parameters: the command name
160
161
returns: listref of column names.
162
163
=cut
164
165
sub arguments_for_command {
166
    my $command = shift;
167
168
    # define the fields for this version of the file.
169
    my %format = (
170
        issue   => [qw( cardnumber barcode )],
171
        return  => [qw( barcode )],
172
        payment => [qw( cardnumber amount )],
173
    );
174
175
    return $format{$command};
176
}
177
178
=head2 _get_borrowernumber_from_barcode
179
180
pass in a barcode
181
get back the borrowernumber of the patron who has it checked out.
182
undef if that can't be found
183
184
=cut
185
186
sub _get_borrowernumber_from_barcode {
187
    my $barcode = shift;
188
189
    return unless $barcode;
190
191
    my $item = GetBiblioFromItemNumber( undef, $barcode );
192
    return unless $item->{'itemnumber'};
193
194
    my $issue = C4::Circulation::GetItemIssue( $item->{'itemnumber'} );
195
    return unless $issue->{'borrowernumber'};
196
    return $issue->{'borrowernumber'};
197
}
(-)a/offline_circ/list.pl (-1 / +1 lines)
Lines 54-59 for (@$operations) { Link Here
54
    }
54
    }
55
    $_->{'actionissue'}    = $_->{'action'} eq 'issue';
55
    $_->{'actionissue'}    = $_->{'action'} eq 'issue';
56
    $_->{'actionreturn'}   = $_->{'action'} eq 'return';
56
    $_->{'actionreturn'}   = $_->{'action'} eq 'return';
57
    $_->{'actionpayment'}  = $_->{'action'} eq 'payment';
57
}
58
}
58
$template->param(pending_operations => $operations);
59
$template->param(pending_operations => $operations);
59
60
60
- 

Return to bug 8220