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

(-)a/Koha/REST/V1/Accountline.pm (+37 lines)
Lines 19-26 use Modern::Perl; Link Here
19
19
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
21
22
use Scalar::Util qw( looks_like_number );
23
22
use C4::Auth qw( haspermission );
24
use C4::Auth qw( haspermission );
23
use Koha::Account::Lines;
25
use Koha::Account::Lines;
26
use Koha::Account;
24
27
25
sub list {
28
sub list {
26
    my ($c, $args, $cb) = @_;
29
    my ($c, $args, $cb) = @_;
Lines 48-51 sub edit { Link Here
48
    return $c->$cb($accountline->unblessed(), 200);
51
    return $c->$cb($accountline->unblessed(), 200);
49
}
52
}
50
53
54
55
sub pay {
56
    my ($c, $args, $cb) = @_;
57
58
    my $accountline = Koha::Account::Lines->find($args->{accountlines_id});
59
    unless ($accountline) {
60
        return $c->$cb({error => "Accountline not found"}, 404);
61
    }
62
63
    my $body = $c->req->json;
64
    my $amount = defined $body->{amount};
65
    my $note = $body->{note} || '';
66
67
    if ($amount && !looks_like_number($amount)) {
68
        return $c->$cb({error => "Invalid amount"}, 400);
69
    }
70
71
    Koha::Account->new(
72
        {
73
            patron_id => $accountline->borrowernumber,
74
        }
75
      )->pay(
76
        {
77
            lines  => [$accountline],
78
            amount => $amount,
79
            note => $note,
80
        }
81
      );
82
83
    $accountline = Koha::Account::Lines->find($args->{accountlines_id});
84
    return $c->$cb($accountline->unblessed(), 200);
85
}
86
87
51
1;
88
1;
(-)a/Koha/REST/V1/Patron.pm (+34 lines)
Lines 19-25 use Modern::Perl; Link Here
19
19
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
21
22
use Scalar::Util qw( looks_like_number );
23
24
use C4::Auth qw( haspermission );
22
use Koha::Patrons;
25
use Koha::Patrons;
26
use Koha::Account;
23
27
24
sub list {
28
sub list {
25
    my ($c, $args, $cb) = @_;
29
    my ($c, $args, $cb) = @_;
Lines 44-47 sub get { Link Here
44
    return $c->$cb($patron->unblessed, 200);
48
    return $c->$cb($patron->unblessed, 200);
45
}
49
}
46
50
51
sub pay {
52
    my ($c, $args, $cb) = @_;
53
54
    my $patron = Koha::Patrons->find($args->{borrowernumber});
55
    unless ($patron) {
56
        return $c->$cb({error => "Patron not found"}, 404);
57
    }
58
59
    my $body = $c->req->json;
60
    my $amount = $body->{amount};
61
    my $note = $body->{note} || '';
62
63
    unless ($amount && looks_like_number($amount)) {
64
        return $c->$cb({error => "Invalid amount"}, 400);
65
    }
66
67
    Koha::Account->new(
68
        {
69
            patron_id => $args->{borrowernumber},
70
        }
71
      )->pay(
72
        {
73
            amount => $amount,
74
            note => $note,
75
        }
76
      );
77
78
    return $c->$cb('', 204);
79
}
80
47
1;
81
1;
(-)a/api/v1/swagger/paths.json (+6 lines)
Lines 11-16 Link Here
11
  "/accountlines/{accountlines_id}": {
11
  "/accountlines/{accountlines_id}": {
12
    "$ref": "paths/accountlines.json#/~1accountlines~1{accountlines_id}"
12
    "$ref": "paths/accountlines.json#/~1accountlines~1{accountlines_id}"
13
  },
13
  },
14
  "/accountlines/{accountlines_id}/payment": {
15
    "$ref": "paths/accountlines.json#/~1accountlines~1{accountlines_id}~1payment"
16
  },
14
  "/holds": {
17
  "/holds": {
15
    "$ref": "paths/holds.json#/~1holds"
18
    "$ref": "paths/holds.json#/~1holds"
16
  },
19
  },
Lines 22-26 Link Here
22
  },
25
  },
23
  "/patrons/{borrowernumber}": {
26
  "/patrons/{borrowernumber}": {
24
    "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}"
27
    "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}"
28
  },
29
  "/patrons/{borrowernumber}/payment": {
30
    "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}~1payment"
25
  }
31
  }
26
}
32
}
(-)a/api/v1/swagger/paths/accountlines.json (+55 lines)
Lines 93-97 Link Here
93
        }
93
        }
94
      }
94
      }
95
    }
95
    }
96
  },
97
  "/accountlines/{accountlines_id}/payment": {
98
    "post": {
99
      "operationId": "payAccountlines",
100
      "tags": ["accountlines"],
101
      "produces": [
102
        "application/json"
103
      ],
104
      "parameters": [
105
        { "$ref": "../parameters.json#/accountlinesIdPathParam" },
106
        {
107
          "name": "body",
108
          "in": "body",
109
          "description": "A JSON object containing fields to modify",
110
          "schema": {
111
            "type": "object",
112
            "properties": {
113
              "amount": {
114
                "description": "Amount to pay"
115
              },
116
              "note": {
117
                "description": "Payment note"
118
              }
119
            }
120
          }
121
        }
122
      ],
123
      "consumes": ["application/json"],
124
      "produces": ["application/json"],
125
      "responses": {
126
        "200": {
127
          "description": "Paid accountline",
128
          "schema": { "$ref": "../definitions.json#/accountline" }
129
        },
130
        "400": {
131
          "description": "Missing or wrong parameters",
132
          "schema": { "$ref": "../definitions.json#/error" }
133
        },
134
        "403": {
135
          "description": "Access forbidden",
136
          "schema": {
137
            "$ref": "../definitions.json#/error"
138
          }
139
        },
140
        "404": {
141
          "description": "Accountline not found",
142
          "schema": { "$ref": "../definitions.json#/error" }
143
        }
144
      },
145
      "x-koha-authorization": {
146
        "permissions": {
147
          "updatecharges": "1"
148
        }
149
      }
150
    }
96
  }
151
  }
97
}
152
}
(-)a/api/v1/swagger/paths/patrons.json (+55 lines)
Lines 69-73 Link Here
69
        }
69
        }
70
      }
70
      }
71
    }
71
    }
72
  },
73
  "/patrons/{borrowernumber}/payment": {
74
    "post": {
75
      "operationId": "payForPatron",
76
      "tags": ["accountlines"],
77
      "produces": [
78
        "application/json"
79
      ],
80
      "parameters": [
81
        { "$ref": "../parameters.json#/borrowernumberPathParam" },
82
        {
83
          "name": "body",
84
          "in": "body",
85
          "description": "A JSON object containing fields to modify",
86
          "required": true,
87
          "schema": {
88
            "type": "object",
89
            "properties": {
90
              "amount": {
91
                "description": "Amount to pay"
92
              },
93
              "note": {
94
                "description": "Payment note"
95
              }
96
            }
97
          }
98
        }
99
      ],
100
      "consumes": ["application/json"],
101
      "produces": ["application/json"],
102
      "responses": {
103
        "204": {
104
          "description": "Success"
105
        },
106
        "400": {
107
          "description": "Missing or wrong parameters",
108
          "schema": { "$ref": "../definitions.json#/error" }
109
        },
110
        "403": {
111
          "description": "Access forbidden",
112
          "schema": {
113
            "$ref": "../definitions.json#/error"
114
          }
115
        },
116
        "404": {
117
          "description": "Borrower not found",
118
          "schema": { "$ref": "../definitions.json#/error" }
119
        }
120
      },
121
      "x-koha-authorization": {
122
        "permissions": {
123
          "updatecharges": "1"
124
        }
125
      }
126
    }
72
  }
127
  }
73
}
128
}
(-)a/t/db_dependent/api/v1/accountlines.t (-5 / +57 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 22;
20
21
use Test::More tests => 37;
21
use Test::Mojo;
22
use Test::Mojo;
22
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
23
24
Lines 45-50 $t->get_ok('/api/v1/accountlines') Link Here
45
$t->put_ok("/api/v1/accountlines/11224409" => json => {'amount' => -5})
46
$t->put_ok("/api/v1/accountlines/11224409" => json => {'amount' => -5})
46
    ->status_is(401);
47
    ->status_is(401);
47
48
49
$t->post_ok("/api/v1/accountlines/11224408/payment")
50
    ->status_is(401);
51
48
my $loggedinuser = $builder->build({
52
my $loggedinuser = $builder->build({
49
    source => 'Borrower',
53
    source => 'Borrower',
50
    value => {
54
    value => {
Lines 75-82 my $borrowernumber2 = $borrower2->{borrowernumber}; Link Here
75
79
76
$dbh->do(q| DELETE FROM accountlines |);
80
$dbh->do(q| DELETE FROM accountlines |);
77
$dbh->do(q|
81
$dbh->do(q|
78
    INSERT INTO accountlines (borrowernumber, amount, accounttype)
82
    INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding)
79
    VALUES (?, 20, 'A'), (?, 40, 'F'), (?, 80, 'F'), (?, 10, 'F')
83
    VALUES (?, 20, 'A', 20), (?, 40, 'F', 40), (?, 80, 'F', 80), (?, 10, 'F', 10)
80
    |, undef, $borrowernumber, $borrowernumber, $borrowernumber, $borrowernumber2);
84
    |, undef, $borrowernumber, $borrowernumber, $borrowernumber, $borrowernumber2);
81
85
82
my $session = C4::Auth::get_session('');
86
my $session = C4::Auth::get_session('');
Lines 127-133 my $put_data = { Link Here
127
131
128
$tx = $t->ua->build_tx(
132
$tx = $t->ua->build_tx(
129
    PUT => "/api/v1/accountlines/11224409"
133
    PUT => "/api/v1/accountlines/11224409"
130
        => {Accept => '*/*'}
131
        => json => $put_data);
134
        => json => $put_data);
132
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
135
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
133
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
136
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
Lines 144-150 $t->request_ok($tx) Link Here
144
147
145
$tx = $t->ua->build_tx(
148
$tx = $t->ua->build_tx(
146
    PUT => "/api/v1/accountlines/$accountline_to_edit->{accountlines_id}"
149
    PUT => "/api/v1/accountlines/$accountline_to_edit->{accountlines_id}"
147
        => {Accept => '*/*'}
148
        => json => $put_data);
150
        => json => $put_data);
149
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
151
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
150
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
152
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
Lines 158-162 is($accountline_edited->{amountoutstanding}, '-19.000000'); Link Here
158
160
159
161
160
# Payment tests
162
# Payment tests
163
$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/4562765765/payment");
164
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
165
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
166
$t->request_ok($tx)
167
  ->status_is(404);
168
169
my $accountline_to_pay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 20})->unblessed()->[0];
170
$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_pay->{accountlines_id}/payment");
171
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
172
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
173
$t->request_ok($tx)
174
  ->status_is(200);
175
#$t->content_is('toto');
176
177
my $accountline_paid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => -20})->unblessed()->[0];
178
ok($accountline_paid);
179
180
# Partial payment tests
181
my $post_data = {
182
    'amount' => 17,
183
    'note' => 'Partial payment'
184
};
185
186
$tx = $t->ua->build_tx(
187
    POST => "/api/v1/accountlines/11224419/payment"
188
        => json => $post_data);
189
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
190
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
191
$t->request_ok($tx)
192
    ->status_is(404);
193
194
my $accountline_to_partiallypay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0];
195
196
$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/payment" => json => {amount => 'foo'});
197
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
198
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
199
$t->request_ok($tx)
200
  ->status_is(400);
201
202
$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/payment" => json => $post_data);
203
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
204
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
205
$t->request_ok($tx)
206
  ->status_is(200);
207
208
$accountline_to_partiallypay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0];
209
is($accountline_to_partiallypay->{amountoutstanding}, '63.000000');
210
211
my $accountline_partiallypaid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => -17})->unblessed()->[0];
212
ok($accountline_partiallypaid);
161
213
162
$dbh->rollback;
214
$dbh->rollback;
(-)a/t/db_dependent/api/v1/patrons.t (-3 / +56 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 20;
20
21
use Test::More tests => 31;
21
use Test::Mojo;
22
use Test::Mojo;
22
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
23
24
Lines 26-31 use C4::Context; Link Here
26
27
27
use Koha::Database;
28
use Koha::Database;
28
use Koha::Patron;
29
use Koha::Patron;
30
use Koha::Account::Lines;
29
31
30
my $builder = t::lib::TestBuilder->new();
32
my $builder = t::lib::TestBuilder->new();
31
33
Lines 105-111 my $loggedinuser = $builder->build({ Link Here
105
    value => {
107
    value => {
106
        branchcode   => $branchcode,
108
        branchcode   => $branchcode,
107
        categorycode => $categorycode,
109
        categorycode => $categorycode,
108
        flags        => 16 # borrowers flag
110
        flags        => 1040 # borrowers and updatecharges (2^4 | 2^10)
109
    }
111
    }
110
});
112
});
111
113
Lines 129-132 $t->request_ok($tx) Link Here
129
  ->json_is('/borrowernumber' => $borrower->{ borrowernumber })
131
  ->json_is('/borrowernumber' => $borrower->{ borrowernumber })
130
  ->json_is('/surname' => $borrower->{ surname });
132
  ->json_is('/surname' => $borrower->{ surname });
131
133
134
135
# Payment tests
136
my $borrower2 = $builder->build({
137
    source => 'Borrower',
138
    value => {
139
        branchcode   => $branchcode,
140
        categorycode => $categorycode,
141
    }
142
});
143
my $borrowernumber2 = $borrower2->{borrowernumber};
144
145
$dbh->do(q|
146
    INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding)
147
    VALUES (?, 26, 'A', 26)
148
    |, undef, $borrowernumber2);
149
150
$t->post_ok("/api/v1/patrons/$borrowernumber2/payment" => json => {'amount' => 8})
151
    ->status_is(401);
152
153
my $post_data2 = {
154
    'amount' => 24,
155
    'note' => 'Partial payment'
156
};
157
158
$tx = $t->ua->build_tx(POST => "/api/v1/patrons/8789798797/payment" => json => $post_data2);
159
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
160
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
161
$t->request_ok($tx)
162
  ->status_is(404);
163
164
$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => {amount => 0});
165
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
166
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
167
$t->request_ok($tx)
168
  ->status_is(400);
169
170
$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => {amount => 'foo'});
171
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
172
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
173
$t->request_ok($tx)
174
  ->status_is(400);
175
176
$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => $post_data2);
177
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
178
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
179
$t->request_ok($tx)
180
  ->status_is(204);
181
182
my $accountline_partiallypaid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber2, 'amount' => 26})->unblessed()->[0];
183
184
is($accountline_partiallypaid->{amountoutstanding}, '2.000000');
185
132
$dbh->rollback;
186
$dbh->rollback;
133
- 

Return to bug 15165