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

(-)a/C4/Circulation.pm (-2 / +15 lines)
Lines 3234-3242 sub GetOfflineOperation { Link Here
3234
}
3234
}
3235
3235
3236
sub AddOfflineOperation {
3236
sub AddOfflineOperation {
3237
    my ( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount ) = @_;
3237
    my $dbh = C4::Context->dbh;
3238
    my $dbh = C4::Context->dbh;
3238
    my $sth = $dbh->prepare("INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber) VALUES(?,?,?,?,?,?)");
3239
    my $sth = $dbh->prepare("INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber, amount) VALUES(?,?,?,?,?,?,?)");
3239
    $sth->execute( @_ );
3240
    $sth->execute( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount );
3240
    return "Added.";
3241
    return "Added.";
3241
}
3242
}
3242
3243
Lines 3255-3260 sub ProcessOfflineOperation { Link Here
3255
        $report = ProcessOfflineReturn( $operation );
3256
        $report = ProcessOfflineReturn( $operation );
3256
    } elsif ( $operation->{action} eq 'issue' ) {
3257
    } elsif ( $operation->{action} eq 'issue' ) {
3257
        $report = ProcessOfflineIssue( $operation );
3258
        $report = ProcessOfflineIssue( $operation );
3259
    } elsif ( $operation->{action} eq 'payment' ) {
3260
        $report = ProcessOfflinePayment( $operation );
3258
    }
3261
    }
3259
3262
3260
    DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid};
3263
    DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid};
Lines 3324-3329 sub ProcessOfflineIssue { Link Here
3324
    }
3327
    }
3325
}
3328
}
3326
3329
3330
sub ProcessOfflinePayment {
3331
    my $operation = shift;
3332
3333
    my $borrower = C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ); # Get borrower from operation cardnumber
3334
    my $amount = $operation->{amount};
3335
3336
    recordpayment( $borrower->{borrowernumber}, $amount );
3337
3338
    return "Success."
3339
}
3327
3340
3328
3341
3329
=head2 TransferSlip
3342
=head2 TransferSlip
(-)a/installer/data/mysql/kohastructure.sql (-9 / +9 lines)
Lines 1553-1569 CREATE TABLE `patronimage` ( -- information related to patron images Link Here
1553
-- so MyISAM is better in this case
1553
-- so MyISAM is better in this case
1554
1554
1555
DROP TABLE IF EXISTS `pending_offline_operations`;
1555
DROP TABLE IF EXISTS `pending_offline_operations`;
1556
CREATE TABLE `pending_offline_operations` (
1556
CREATE TABLE pending_offline_operations (
1557
  `operationid` int(11) NOT NULL AUTO_INCREMENT,
1557
  operationid int(11) NOT NULL AUTO_INCREMENT,
1558
  `userid` varchar(30) NOT NULL,
1558
  userid varchar(30) NOT NULL,
1559
  `branchcode` varchar(10) NOT NULL,
1559
  branchcode varchar(10) NOT NULL,
1560
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
1560
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
1561
  `action` varchar(10) NOT NULL,
1561
  `action` varchar(10) NOT NULL,
1562
  `barcode` varchar(20) NOT NULL,
1562
  barcode varchar(20) DEFAULT NULL,
1563
  `cardnumber` varchar(16) DEFAULT NULL,
1563
  cardnumber varchar(16) DEFAULT NULL,
1564
  PRIMARY KEY (`operationid`)
1564
  amount decimal(28,6) DEFAULT NULL,
1565
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
1565
  PRIMARY KEY (operationid)
1566
1566
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
1567
1567
1568
1568
1569
--
1569
--
(-)a/installer/data/mysql/updatedatabase.pl (+8 lines)
Lines 5827-5832 if(C4::Context->preference("Version") < TransformToNum($DBversion) ) { Link Here
5827
    SetVersion($DBversion);
5827
    SetVersion($DBversion);
5828
}
5828
}
5829
5829
5830
$DBversion = "3.09.00.XXX";
5831
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
5832
    $dbh->do("ALTER TABLE `pending_offline_operations` CHANGE `barcode` `barcode` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
5833
    $dbh->do("ALTER TABLE `pending_offline_operations` ADD `amount` DECIMAL( 28, 6 ) NULL DEFAULT NULL");
5834
    print "Upgrade to $DBversion done (redefine the field branchcode as PRIMARY KEY of branches)\n";
5835
    SetVersion ($DBversion);
5836
}
5837
5830
=head1 FUNCTIONS
5838
=head1 FUNCTIONS
5831
5839
5832
=head2 TableExists($table)
5840
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt (-2 / +6 lines)
Lines 51-58 Link Here
51
	<div class="yui-u">
51
	<div class="yui-u">
52
        <h5>Offline circulation</h5>
52
        <h5>Offline circulation</h5>
53
		<ul>
53
		<ul>
54
            <li><a href="/cgi-bin/koha/offline_circ/process_koc.pl">Offline circulation file (.koc) uploader</a></li>
54
                    <li><a href="/cgi-bin/koha/offline_circ/process_koc.pl">Upload offline circulation file (.koc)</a></li>
55
            <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>
55
                    <li><a href="/cgi-bin/koha/offline_circ/list.pl">Pending offline circulation actions</a>
56
                    <ul>
57
                        <li><a href="http://kylehall.info/index.php/projects/koha/koha-offline-circulation/">Get desktop application</a></li>
58
                        <li><a href="https://addons.mozilla.org/[% lang %]/firefox/addon/koct/">Get Firefox add-on</a></li>
59
                    </ul>
56
		</ul>
60
		</ul>
57
	</div>
61
	</div>
58
</div>
62
</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