From b3af49ee7654d64d43c63fd8ddfaaa9f81dcabde Mon Sep 17 00:00:00 2001 From: Alex Arnaud Date: Thu, 12 Nov 2015 14:44:47 +0100 Subject: [PATCH] Bug 15165 - Add API routes to pay accountlines POST /accountlines/(:accountlines_id)/payment (pay towards accountline) POST /patrons/(:borrowernumber)/payment (pay towards borrower) Test plan: 1. Open a browser tab on Koha staff and log in (to create CGISESSID cookie). You must have permission updatecharges. 2. Create a fine to any patron and get the accountlines_id. 3. Send POST request to http://yourlibrary/api/v1/accountlines/YYY/payment without body where YYY is the accountlines_id you created in step 2. 4. Check that the accountline that you created in step 2 is paid. 5. Create two payments with amount 5.00 (with no other outstanding payments) 6. Send POST request to http://yourlibrary/api/v1/patrons/ZZZ/payment with body {"amount": 10} Replace ZZZ with the borrowernumber for which you have created two fines 7. Check that the two accountlines are paid. 8. Repeat step 2. 9. Send POST request to http://yourlibrary/api/v1/accountlines/YYY/payment with body {"amount": XXX} Replace YYY with the accountlines_id you created in step 8. Set amount (XXX) to the half of the amount of the fine you created in step 8. 10. Check that the fine is still outstanding with half of the original amount. 11. Run unit tests at t/db_dependent/api/v1/accountlines.t and t/db_dependent/api/v1/patrons.t --- Koha/REST/V1/Accountline.pm | 42 +++++++++++++++++++++++ Koha/REST/V1/Patron.pm | 38 +++++++++++++++++++++ api/v1/swagger/paths.json | 6 ++++ api/v1/swagger/paths/accountlines.json | 50 ++++++++++++++++++++++++++++ api/v1/swagger/paths/patrons.json | 50 ++++++++++++++++++++++++++++ api/v1/swagger/swagger.min.json | 2 +- t/db_dependent/api/v1/accountlines.t | 61 +++++++++++++++++++++++++++++++--- t/db_dependent/api/v1/patrons.t | 58 ++++++++++++++++++++++++++++++-- 8 files changed, 299 insertions(+), 8 deletions(-) diff --git a/Koha/REST/V1/Accountline.pm b/Koha/REST/V1/Accountline.pm index f1aa7e0..ebf1040 100644 --- a/Koha/REST/V1/Accountline.pm +++ b/Koha/REST/V1/Accountline.pm @@ -19,8 +19,11 @@ use Modern::Perl; use Mojo::Base 'Mojolicious::Controller'; +use Scalar::Util qw( looks_like_number ); + use C4::Auth qw( haspermission ); use Koha::Account::Lines; +use Koha::Account; sub list { my ($c, $args, $cb) = @_; @@ -58,4 +61,43 @@ sub edit { return $c->$cb($accountline->unblessed(), 200); } + +sub pay { + my ($c, $args, $cb) = @_; + + my $user = $c->stash('koha.user'); + unless ($user && haspermission($user->userid, {updatecharges => 1})) { + return $c->$cb({error => "You don't have the required permission"}, 403); + } + + my $accountline = Koha::Account::Lines->find($args->{accountlines_id}); + unless ($accountline) { + return $c->$cb({error => "Accountline not found"}, 404); + } + + my $body = $c->req->json; + my $amount = $body->{amount}; + my $note = $body->{note} || ''; + + if ($amount && !looks_like_number($amount)) { + return $c->$cb({error => "Invalid amount"}, 400); + } + + Koha::Account->new( + { + patron_id => $accountline->borrowernumber, + } + )->pay( + { + lines => [$accountline], + amount => $amount, + note => $note, + } + ); + + $accountline = Koha::Account::Lines->find($args->{accountlines_id}); + return $c->$cb($accountline->unblessed(), 200); +} + + 1; diff --git a/Koha/REST/V1/Patron.pm b/Koha/REST/V1/Patron.pm index 2851308..c5894eb 100644 --- a/Koha/REST/V1/Patron.pm +++ b/Koha/REST/V1/Patron.pm @@ -19,8 +19,11 @@ use Modern::Perl; use Mojo::Base 'Mojolicious::Controller'; +use Scalar::Util qw( looks_like_number ); + use C4::Auth qw( haspermission ); use Koha::Patrons; +use Koha::Account; sub list { my ($c, $args, $cb) = @_; @@ -55,4 +58,39 @@ sub get { return $c->$cb($patron->unblessed, 200); } +sub pay { + my ($c, $args, $cb) = @_; + + my $user = $c->stash('koha.user'); + unless ($user && haspermission($user->userid, {updatecharges => 1})) { + return $c->$cb({error => "You don't have the required permission"}, 403); + } + + my $patron = Koha::Patrons->find($args->{borrowernumber}); + unless ($patron) { + return $c->$cb({error => "Patron not found"}, 404); + } + + my $body = $c->req->json; + my $amount = $body->{amount}; + my $note = $body->{note} || ''; + + unless ($amount && looks_like_number($amount)) { + return $c->$cb({error => "Invalid amount"}, 400); + } + + Koha::Account->new( + { + patron_id => $args->{borrowernumber}, + } + )->pay( + { + amount => $amount, + note => $note, + } + ); + + return $c->$cb('', 204); +} + 1; diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index e00dffc..39c7f9f 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -5,6 +5,9 @@ "/accountlines/{accountlines_id}": { "$ref": "paths/accountlines.json#/~1accountlines~1{accountlines_id}" }, + "/accountlines/{accountlines_id}/payment": { + "$ref": "paths/accountlines.json#/~1accountlines~1{accountlines_id}~1payment" + }, "/holds": { "$ref": "paths/holds.json#/~1holds" }, @@ -16,5 +19,8 @@ }, "/patrons/{borrowernumber}": { "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}" + }, + "/patrons/{borrowernumber}/payment": { + "$ref": "paths/patrons.json#/~1patrons~1{borrowernumber}~1payment" } } diff --git a/api/v1/swagger/paths/accountlines.json b/api/v1/swagger/paths/accountlines.json index 89b0ff4..3dbf3c2 100644 --- a/api/v1/swagger/paths/accountlines.json +++ b/api/v1/swagger/paths/accountlines.json @@ -81,5 +81,55 @@ } } } + }, + "/accountlines/{accountlines_id}/payment": { + "post": { + "operationId": "payAccountlines", + "tags": ["accountlines"], + "produces": [ + "application/json" + ], + "parameters": [ + { "$ref": "../parameters.json#/accountlinesIdPathParam" }, + { + "name": "body", + "in": "body", + "description": "A JSON object containing fields to modify", + "schema": { + "type": "object", + "properties": { + "amount": { + "description": "Amount to pay" + }, + "note": { + "description": "Payment note" + } + } + } + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "responses": { + "200": { + "description": "Paid accountline", + "schema": { "$ref": "../definitions.json#/accountline" } + }, + "400": { + "description": "Missing or wrong parameters", + "schema": { "$ref": "../definitions.json#/error" } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Accountline not found", + "schema": { "$ref": "../definitions.json#/error" } + } + } + } } } diff --git a/api/v1/swagger/paths/patrons.json b/api/v1/swagger/paths/patrons.json index f7c6400..07c4057 100644 --- a/api/v1/swagger/paths/patrons.json +++ b/api/v1/swagger/paths/patrons.json @@ -57,5 +57,55 @@ } } } + }, + "/patrons/{borrowernumber}/payment": { + "post": { + "operationId": "payForPatron", + "tags": ["accountlines"], + "produces": [ + "application/json" + ], + "parameters": [ + { "$ref": "../parameters.json#/borrowernumberPathParam" }, + { + "name": "body", + "in": "body", + "description": "A JSON object containing fields to modify", + "required": true, + "schema": { + "type": "object", + "properties": { + "amount": { + "description": "Amount to pay" + }, + "note": { + "description": "Payment note" + } + } + } + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "responses": { + "204": { + "description": "Success" + }, + "400": { + "description": "Missing or wrong parameters", + "schema": { "$ref": "../definitions.json#/error" } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Borrower not found", + "schema": { "$ref": "../definitions.json#/error" } + } + } + } } } diff --git a/api/v1/swagger/swagger.min.json b/api/v1/swagger/swagger.min.json index 512a3be..5b76c7f 100644 --- a/api/v1/swagger/swagger.min.json +++ b/api/v1/swagger/swagger.min.json @@ -1 +1 @@ -{"swagger":"2.0","x-primitives":{"phone":{"type":["string","null"],"description":"primary phone number for patron's primary address"},"reserve_id":{"description":"Internal hold identifier"},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"email":{"description":"primary email address for patron's primary address","type":["string","null"]},"firstname":{"description":"patron's first name","type":["string","null"]},"cardnumber":{"description":"library assigned user identifier","type":["string","null"]},"surname":{"type":"string","description":"patron's last name"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]}},"info":{"title":"Koha REST API","license":{"url":"http:\/\/www.gnu.org\/licenses\/gpl.txt","name":"GPL v3"},"contact":{"url":"http:\/\/koha-community.org\/","name":"Koha Team"},"version":"1"},"paths":{"\/patrons\/{borrowernumber}":{"get":{"responses":{"403":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"description":"Access forbidden"},"200":{"schema":{"type":"object","properties":{"B_phone":{"type":["string","null"],"description":"phone number for patron's alternate address"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"categorycode":{"type":"string","description":"code of patron's category"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"initials":{"type":["string","null"],"description":"initials of the patron"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"checkprevcheckout":{"type":"string","description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"sort1":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"altcontactaddress3":{"type":["string","null"],"description":"the city for the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"dateofbirth":{"description":"patron's date of birth","type":["string","null"]},"state":{"description":"state or province of patron's primary address","type":["string","null"]},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"updated_on":{"description":"time of last change could be useful for synchronization with external systems (among others)","type":"string"},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"contacttitle":{"description":"used for children to include title of guarantor","type":["string","null"]},"sex":{"type":["string","null"],"description":"patron's gender"},"B_streetnumber":{"description":"street number of patron's alternate address","type":["string","null"]},"contactnote":{"description":"a note related to patron's alternate address","type":["string","null"]},"mobile":{"description":"the other phone number for patron's primary address","type":["string","null"]},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"lost":{"type":["string","null"],"description":"set to 1 if library marked this patron as having lost his card"},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"phonepro":{"type":["string","null"],"description":"secondary phone number for patron's primary address"},"country":{"description":"country of patron's primary address","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"title":{"type":["string","null"],"description":"patron's title"},"password":{"type":["string","null"],"description":"patron's encrypted password"},"city":{"description":"city or town of patron's primary address","type":"string"},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactcountry":{"description":"the country for the alternate contact for the patron","type":["string","null"]},"email":{"description":"primary email address for patron's primary address","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"debarred":{"description":"until this date the patron can only check-in","type":["string","null"]},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"sort2":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"userid":{"type":["string","null"],"description":"patron's login"},"surname":{"type":"string","description":"patron's last name"},"B_zipcode":{"description":"zip or postal code of patron's alternate address","type":["string","null"]},"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"sms_provider_id":{"description":"the provider of the mobile phone number defined in smsalertnumber","type":["string","null"]},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"address":{"description":"first address line of patron's primary address","type":"string"},"altcontactfirstname":{"type":["string","null"],"description":"first name of alternate contact for the patron"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"dateenrolled":{"type":["string","null"],"description":"date the patron was added to Koha"},"B_country":{"description":"country of patron's alternate address","type":["string","null"]},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"debarredcomment":{"type":["string","null"],"description":"comment on the stop of the patron"},"B_address":{"description":"first address line of patron's alternate address","type":["string","null"]},"smsalertnumber":{"type":["string","null"],"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)"}}},"description":"A patron"},"404":{"description":"Patron not found","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}}},"operationId":"getPatron","parameters":[{"name":"borrowernumber","in":"path","required":true,"description":"Internal patron identifier","type":"integer"}],"produces":["application\/json"],"tags":["patrons"]}},"\/holds":{"post":{"produces":["application\/json"],"consumes":["application\/json"],"operationId":"addHold","parameters":[{"name":"body","schema":{"type":"object","properties":{"expirationdate":{"format":"date","description":"Hold end date","type":"string"},"branchcode":{"type":"string","description":"Pickup location"},"biblionumber":{"description":"Biblio internal identifier","type":"integer"},"borrowernumber":{"type":"integer","description":"Borrower internal identifier"},"itemnumber":{"description":"Item internal identifier","type":"integer"}}},"required":true,"in":"body","description":"A JSON object containing informations about the new hold"}],"responses":{"403":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Hold not allowed"},"400":{"description":"Missing or wrong parameters","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}},"500":{"description":"Internal error","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}},"404":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Borrower not found"},"201":{"description":"Created hold","schema":{"properties":{"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"reserve_id":{"description":"Internal hold identifier"},"reservedate":{"description":"the date the hold was placed"},"suspend_until":{"description":""},"notificationdate":{"description":"currently unused"},"cancellationdate":{"description":"the date the hold was cancelled"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]},"suspend":{"description":""},"reservenotes":{"description":"notes related to this hold"},"itemtype":{"type":["string","null"],"description":"If record level hold, the optional itemtype of the item the patron is requesting"},"timestamp":{"description":"date and time the hold was last updated"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"expirationdate":{"description":"the date the hold expires"},"priority":{"description":"where in the queue the patron sits"},"reminderdate":{"description":"currently unused"},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"lowestPriority":{"description":""}},"type":"object"}}},"tags":["borrowers","holds"]},"get":{"responses":{"404":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Borrower not found"},"200":{"description":"A list of holds","schema":{"type":"array","items":{"properties":{"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"reserve_id":{"description":"Internal hold identifier"},"reservedate":{"description":"the date the hold was placed"},"suspend_until":{"description":""},"notificationdate":{"description":"currently unused"},"cancellationdate":{"description":"the date the hold was cancelled"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]},"suspend":{"description":""},"reservenotes":{"description":"notes related to this hold"},"itemtype":{"type":["string","null"],"description":"If record level hold, the optional itemtype of the item the patron is requesting"},"timestamp":{"description":"date and time the hold was last updated"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"expirationdate":{"description":"the date the hold expires"},"priority":{"description":"where in the queue the patron sits"},"reminderdate":{"description":"currently unused"},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"lowestPriority":{"description":""}},"type":"object"}}}},"operationId":"listHolds","parameters":[{"name":"reserve_id","in":"query","type":"integer","description":"Internal reserve identifier"},{"name":"borrowernumber","in":"query","description":"Internal borrower identifier","type":"integer"},{"name":"reservedate","in":"query","description":"Reserve date","type":"string"},{"name":"biblionumber","in":"query","description":"Internal biblio identifier","type":"integer"},{"name":"branchcode","in":"query","description":"Branch code","type":"string"},{"description":"Notification date","type":"string","in":"query","name":"notificationdate"},{"name":"reminderdate","description":"Reminder date","type":"string","in":"query"},{"name":"cancellationdate","in":"query","description":"Cancellation date","type":"string"},{"in":"query","type":"string","description":"Reserve notes","name":"reservenotes"},{"type":"integer","description":"Priority","in":"query","name":"priority"},{"name":"found","type":"string","description":"Found status","in":"query"},{"in":"query","type":"string","description":"Time of latest update","name":"timestamp"},{"type":"integer","description":"Internal item identifier","in":"query","name":"itemnumber"},{"description":"Date the item was marked as waiting for the patron","type":"string","in":"query","name":"waitingdate"},{"in":"query","type":"string","description":"Date the hold expires","name":"expirationdate"},{"name":"lowestPriority","description":"Lowest priority","type":"integer","in":"query"},{"type":"integer","description":"Suspended","in":"query","name":"suspend"},{"name":"suspend_until","in":"query","description":"Suspended until","type":"string"}],"produces":["application\/json"],"tags":["borrowers","holds"]}},"\/accountlines":{"get":{"responses":{"200":{"description":"A list of accountlines","schema":{"items":{"type":"object","properties":{"note":{"description":"Accountline note"},"accountno":{"description":"?"},"accountlines_id":{"description":"Internal account line identifier"},"date":{"description":"Date when the account line was created"},"itemnumber":{"description":"Internal item identifier"},"accounttype":{"description":"Type of accountline"},"notify_level":{"description":"?"},"timestamp":{"description":"When the account line was last updated"},"amount":{"description":"Amount"},"borrowernumber":{"description":"Internal borrower identifier"},"time":{"description":"Time when the account line was created"},"meansofpayment":{"description":"Means of payment"},"description":{"description":"Description of account line"},"amountoutstanding":{"description":"Amount outstanding"},"notify_id":{"description":"?"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"lastincrement":{"description":"?"}}},"type":"array"}},"403":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Access forbidden"}},"produces":["application\/json"],"operationId":"listAccountlines","tags":["accountlines"]}},"\/patrons":{"get":{"responses":{"200":{"schema":{"type":"array","items":{"type":"object","properties":{"B_phone":{"type":["string","null"],"description":"phone number for patron's alternate address"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"categorycode":{"type":"string","description":"code of patron's category"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"initials":{"type":["string","null"],"description":"initials of the patron"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"checkprevcheckout":{"type":"string","description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"sort1":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"altcontactaddress3":{"type":["string","null"],"description":"the city for the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"dateofbirth":{"description":"patron's date of birth","type":["string","null"]},"state":{"description":"state or province of patron's primary address","type":["string","null"]},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"updated_on":{"description":"time of last change could be useful for synchronization with external systems (among others)","type":"string"},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"contacttitle":{"description":"used for children to include title of guarantor","type":["string","null"]},"sex":{"type":["string","null"],"description":"patron's gender"},"B_streetnumber":{"description":"street number of patron's alternate address","type":["string","null"]},"contactnote":{"description":"a note related to patron's alternate address","type":["string","null"]},"mobile":{"description":"the other phone number for patron's primary address","type":["string","null"]},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"lost":{"type":["string","null"],"description":"set to 1 if library marked this patron as having lost his card"},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"phonepro":{"type":["string","null"],"description":"secondary phone number for patron's primary address"},"country":{"description":"country of patron's primary address","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"title":{"type":["string","null"],"description":"patron's title"},"password":{"type":["string","null"],"description":"patron's encrypted password"},"city":{"description":"city or town of patron's primary address","type":"string"},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactcountry":{"description":"the country for the alternate contact for the patron","type":["string","null"]},"email":{"description":"primary email address for patron's primary address","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"debarred":{"description":"until this date the patron can only check-in","type":["string","null"]},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"sort2":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"userid":{"type":["string","null"],"description":"patron's login"},"surname":{"type":"string","description":"patron's last name"},"B_zipcode":{"description":"zip or postal code of patron's alternate address","type":["string","null"]},"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"sms_provider_id":{"description":"the provider of the mobile phone number defined in smsalertnumber","type":["string","null"]},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"address":{"description":"first address line of patron's primary address","type":"string"},"altcontactfirstname":{"type":["string","null"],"description":"first name of alternate contact for the patron"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"dateenrolled":{"type":["string","null"],"description":"date the patron was added to Koha"},"B_country":{"description":"country of patron's alternate address","type":["string","null"]},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"debarredcomment":{"type":["string","null"],"description":"comment on the stop of the patron"},"B_address":{"description":"first address line of patron's alternate address","type":["string","null"]},"smsalertnumber":{"type":["string","null"],"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)"}}}},"description":"A list of patrons"},"403":{"description":"Access forbidden","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}}},"produces":["application\/json"],"operationId":"listPatrons","tags":["patrons"]}},"\/accountlines\/{accountlines_id}":{"put":{"responses":{"404":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"description":"Accountline not found"},"400":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Missing or wrong parameters"},"403":{"description":"Access forbidden","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}},"200":{"schema":{"properties":{"note":{"description":"Accountline note"},"accountno":{"description":"?"},"accountlines_id":{"description":"Internal account line identifier"},"date":{"description":"Date when the account line was created"},"itemnumber":{"description":"Internal item identifier"},"accounttype":{"description":"Type of accountline"},"notify_level":{"description":"?"},"timestamp":{"description":"When the account line was last updated"},"amount":{"description":"Amount"},"borrowernumber":{"description":"Internal borrower identifier"},"time":{"description":"Time when the account line was created"},"meansofpayment":{"description":"Means of payment"},"description":{"description":"Description of account line"},"amountoutstanding":{"description":"Amount outstanding"},"notify_id":{"description":"?"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"lastincrement":{"description":"?"}},"type":"object"},"description":"Updated accountline"}},"parameters":[{"name":"accountlines_id","in":"path","required":true,"description":"Internal accountline identifier","type":"integer"},{"schema":{"type":"object","properties":{"amount":{"description":"Amount"},"amountoutstanding":{"description":"Amount outstanding"},"meansofpayment":{"description":"Means of payment"},"note":{"description":"Accountline note"}}},"name":"body","in":"body","required":true,"description":"A JSON object containing fields to modify"}],"operationId":"editAccountlines","produces":["application\/json"],"consumes":["application\/json"],"tags":["accountlines"]}},"\/holds\/{reserve_id}":{"delete":{"parameters":[{"required":true,"in":"path","type":"integer","description":"Internal hold identifier","name":"reserve_id"}],"operationId":"deleteHold","produces":["application\/json"],"responses":{"404":{"description":"Hold not found","schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"}},"200":{"schema":{"type":"object"},"description":"Successful deletion"}},"tags":["holds"]},"put":{"tags":["holds"],"responses":{"400":{"schema":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"description":"Missing or wrong parameters"},"200":{"description":"Updated hold","schema":{"properties":{"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"reserve_id":{"description":"Internal hold identifier"},"reservedate":{"description":"the date the hold was placed"},"suspend_until":{"description":""},"notificationdate":{"description":"currently unused"},"cancellationdate":{"description":"the date the hold was cancelled"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]},"suspend":{"description":""},"reservenotes":{"description":"notes related to this hold"},"itemtype":{"type":["string","null"],"description":"If record level hold, the optional itemtype of the item the patron is requesting"},"timestamp":{"description":"date and time the hold was last updated"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"expirationdate":{"description":"the date the hold expires"},"priority":{"description":"where in the queue the patron sits"},"reminderdate":{"description":"currently unused"},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"lowestPriority":{"description":""}},"type":"object"}},"404":{"description":"Hold not found","schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}}}},"parameters":[{"name":"reserve_id","required":true,"in":"path","type":"integer","description":"Internal hold identifier"},{"description":"A JSON object containing fields to modify","required":true,"in":"body","name":"body","schema":{"type":"object","properties":{"priority":{"description":"Position in waiting queue","type":"integer","minimum":1},"branchcode":{"description":"Pickup location","type":"string"},"suspend_until":{"format":"date","type":"string","description":"Suspend until"}}}}],"operationId":"editHold","consumes":["application\/json"],"produces":["application\/json"]}}},"basePath":"\/api\/v1","definitions":{"accountline":{"properties":{"note":{"description":"Accountline note"},"accountno":{"description":"?"},"accountlines_id":{"description":"Internal account line identifier"},"date":{"description":"Date when the account line was created"},"itemnumber":{"description":"Internal item identifier"},"accounttype":{"description":"Type of accountline"},"notify_level":{"description":"?"},"timestamp":{"description":"When the account line was last updated"},"amount":{"description":"Amount"},"borrowernumber":{"description":"Internal borrower identifier"},"time":{"description":"Time when the account line was created"},"meansofpayment":{"description":"Means of payment"},"description":{"description":"Description of account line"},"amountoutstanding":{"description":"Amount outstanding"},"notify_id":{"description":"?"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"lastincrement":{"description":"?"}},"type":"object"},"patron":{"type":"object","properties":{"B_phone":{"type":["string","null"],"description":"phone number for patron's alternate address"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"categorycode":{"type":"string","description":"code of patron's category"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"initials":{"type":["string","null"],"description":"initials of the patron"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"checkprevcheckout":{"type":"string","description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"sort1":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"altcontactaddress3":{"type":["string","null"],"description":"the city for the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"dateofbirth":{"description":"patron's date of birth","type":["string","null"]},"state":{"description":"state or province of patron's primary address","type":["string","null"]},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"updated_on":{"description":"time of last change could be useful for synchronization with external systems (among others)","type":"string"},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"contacttitle":{"description":"used for children to include title of guarantor","type":["string","null"]},"sex":{"type":["string","null"],"description":"patron's gender"},"B_streetnumber":{"description":"street number of patron's alternate address","type":["string","null"]},"contactnote":{"description":"a note related to patron's alternate address","type":["string","null"]},"mobile":{"description":"the other phone number for patron's primary address","type":["string","null"]},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"lost":{"type":["string","null"],"description":"set to 1 if library marked this patron as having lost his card"},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"phonepro":{"type":["string","null"],"description":"secondary phone number for patron's primary address"},"country":{"description":"country of patron's primary address","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"title":{"type":["string","null"],"description":"patron's title"},"password":{"type":["string","null"],"description":"patron's encrypted password"},"city":{"description":"city or town of patron's primary address","type":"string"},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactcountry":{"description":"the country for the alternate contact for the patron","type":["string","null"]},"email":{"description":"primary email address for patron's primary address","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"debarred":{"description":"until this date the patron can only check-in","type":["string","null"]},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"sort2":{"description":"a field that can be used for any information unique to the library","type":["string","null"]},"userid":{"type":["string","null"],"description":"patron's login"},"surname":{"type":"string","description":"patron's last name"},"B_zipcode":{"description":"zip or postal code of patron's alternate address","type":["string","null"]},"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"sms_provider_id":{"description":"the provider of the mobile phone number defined in smsalertnumber","type":["string","null"]},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"address":{"description":"first address line of patron's primary address","type":"string"},"altcontactfirstname":{"type":["string","null"],"description":"first name of alternate contact for the patron"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"dateenrolled":{"type":["string","null"],"description":"date the patron was added to Koha"},"B_country":{"description":"country of patron's alternate address","type":["string","null"]},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"debarredcomment":{"type":["string","null"],"description":"comment on the stop of the patron"},"B_address":{"description":"first address line of patron's alternate address","type":["string","null"]},"smsalertnumber":{"type":["string","null"],"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)"}}},"holds":{"items":{"properties":{"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"reserve_id":{"description":"Internal hold identifier"},"reservedate":{"description":"the date the hold was placed"},"suspend_until":{"description":""},"notificationdate":{"description":"currently unused"},"cancellationdate":{"description":"the date the hold was cancelled"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]},"suspend":{"description":""},"reservenotes":{"description":"notes related to this hold"},"itemtype":{"type":["string","null"],"description":"If record level hold, the optional itemtype of the item the patron is requesting"},"timestamp":{"description":"date and time the hold was last updated"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"expirationdate":{"description":"the date the hold expires"},"priority":{"description":"where in the queue the patron sits"},"reminderdate":{"description":"currently unused"},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"lowestPriority":{"description":""}},"type":"object"},"type":"array"},"error":{"properties":{"error":{"type":"string","description":"Error message"}},"type":"object"},"hold":{"properties":{"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"reserve_id":{"description":"Internal hold identifier"},"reservedate":{"description":"the date the hold was placed"},"suspend_until":{"description":""},"notificationdate":{"description":"currently unused"},"cancellationdate":{"description":"the date the hold was cancelled"},"itemnumber":{"description":"internally assigned item identifier","type":["string","null"]},"suspend":{"description":""},"reservenotes":{"description":"notes related to this hold"},"itemtype":{"type":["string","null"],"description":"If record level hold, the optional itemtype of the item the patron is requesting"},"timestamp":{"description":"date and time the hold was last updated"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"expirationdate":{"description":"the date the hold expires"},"priority":{"description":"where in the queue the patron sits"},"reminderdate":{"description":"currently unused"},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"lowestPriority":{"description":""}},"type":"object"}},"parameters":{"accountlinesIdPathParam":{"in":"path","required":true,"description":"Internal accountline identifier","type":"integer","name":"accountlines_id"},"borrowernumberPathParam":{"required":true,"in":"path","type":"integer","description":"Internal patron identifier","name":"borrowernumber"},"holdIdPathParam":{"in":"path","required":true,"description":"Internal hold identifier","type":"integer","name":"reserve_id"},"borrowernumberQueryParam":{"in":"query","description":"Internal borrower identifier","type":"integer","name":"borrowernumber"}}} \ No newline at end of file +{"swagger":"2.0","parameters":{"borrowernumberPathParam":{"required":true,"in":"path","description":"Internal patron identifier","type":"integer","name":"borrowernumber"},"holdIdPathParam":{"description":"Internal hold identifier","name":"reserve_id","type":"integer","in":"path","required":true},"borrowernumberQueryParam":{"in":"query","type":"integer","name":"borrowernumber","description":"Internal borrower identifier"},"accountlinesIdPathParam":{"in":"path","required":true,"description":"Internal accountline identifier","type":"integer","name":"accountlines_id"}},"info":{"version":"1","title":"Koha REST API","license":{"name":"GPL v3","url":"http:\/\/www.gnu.org\/licenses\/gpl.txt"},"contact":{"url":"http:\/\/koha-community.org\/","name":"Koha Team"}},"definitions":{"holds":{"items":{"properties":{"suspend_until":{"description":""},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reservedate":{"description":"the date the hold was placed"},"reservenotes":{"description":"notes related to this hold"},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"lowestPriority":{"description":""},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"notificationdate":{"description":"currently unused"},"expirationdate":{"description":"the date the hold expires"},"reminderdate":{"description":"currently unused"},"priority":{"description":"where in the queue the patron sits"},"reserve_id":{"description":"Internal hold identifier"},"cancellationdate":{"description":"the date the hold was cancelled"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"timestamp":{"description":"date and time the hold was last updated"},"itemtype":{"description":"If record level hold, the optional itemtype of the item the patron is requesting","type":["string","null"]},"suspend":{"description":""}},"type":"object"},"type":"array"},"accountline":{"properties":{"meansofpayment":{"description":"Means of payment"},"date":{"description":"Date when the account line was created"},"note":{"description":"Accountline note"},"amount":{"description":"Amount"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"accountlines_id":{"description":"Internal account line identifier"},"time":{"description":"Time when the account line was created"},"lastincrement":{"description":"?"},"accountno":{"description":"?"},"itemnumber":{"description":"Internal item identifier"},"amountoutstanding":{"description":"Amount outstanding"},"notify_level":{"description":"?"},"notify_id":{"description":"?"},"borrowernumber":{"description":"Internal borrower identifier"},"timestamp":{"description":"When the account line was last updated"},"description":{"description":"Description of account line"},"accounttype":{"description":"Type of accountline"}},"type":"object"},"patron":{"type":"object","properties":{"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"B_phone":{"description":"phone number for patron's alternate address","type":["string","null"]},"altcontactfirstname":{"description":"first name of alternate contact for the patron","type":["string","null"]},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"address":{"type":"string","description":"first address line of patron's primary address"},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"smsalertnumber":{"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)","type":["string","null"]},"password":{"type":["string","null"],"description":"patron's encrypted password"},"borrowernumber":{"description":"internally assigned user identifier","type":"string"},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"initials":{"type":["string","null"],"description":"initials of the patron"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"B_country":{"type":["string","null"],"description":"country of patron's alternate address"},"updated_on":{"type":"string","description":"time of last change could be useful for synchronization with external systems (among others)"},"city":{"type":"string","description":"city or town of patron's primary address"},"userid":{"description":"patron's login","type":["string","null"]},"debarred":{"type":["string","null"],"description":"until this date the patron can only check-in"},"lost":{"description":"set to 1 if library marked this patron as having lost his card","type":["string","null"]},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"debarredcomment":{"description":"comment on the stop of the patron","type":["string","null"]},"country":{"type":["string","null"],"description":"country of patron's primary address"},"sex":{"type":["string","null"],"description":"patron's gender"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"categorycode":{"description":"code of patron's category","type":"string"},"contacttitle":{"type":["string","null"],"description":"used for children to include title of guarantor"},"surname":{"type":"string","description":"patron's last name"},"altcontactcountry":{"type":["string","null"],"description":"the country for the alternate contact for the patron"},"title":{"type":["string","null"],"description":"patron's title"},"contactnote":{"type":["string","null"],"description":"a note related to patron's alternate address"},"sms_provider_id":{"type":["string","null"],"description":"the provider of the mobile phone number defined in smsalertnumber"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"altcontactaddress3":{"description":"the city for the alternate contact for the patron","type":["string","null"]},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"mobile":{"type":["string","null"],"description":"the other phone number for patron's primary address"},"B_address":{"type":["string","null"],"description":"first address line of patron's alternate address"},"email":{"type":["string","null"],"description":"primary email address for patron's primary address"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"B_zipcode":{"type":["string","null"],"description":"zip or postal code of patron's alternate address"},"dateofbirth":{"type":["string","null"],"description":"patron's date of birth"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"phonepro":{"description":"secondary phone number for patron's primary address","type":["string","null"]},"dateenrolled":{"description":"date the patron was added to Koha","type":["string","null"]},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"state":{"type":["string","null"],"description":"state or province of patron's primary address"},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"checkprevcheckout":{"description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'","type":"string"},"sort2":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"B_streetnumber":{"type":["string","null"],"description":"street number of patron's alternate address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"sort1":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"}}},"error":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"hold":{"properties":{"suspend_until":{"description":""},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reservedate":{"description":"the date the hold was placed"},"reservenotes":{"description":"notes related to this hold"},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"lowestPriority":{"description":""},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"notificationdate":{"description":"currently unused"},"expirationdate":{"description":"the date the hold expires"},"reminderdate":{"description":"currently unused"},"priority":{"description":"where in the queue the patron sits"},"reserve_id":{"description":"Internal hold identifier"},"cancellationdate":{"description":"the date the hold was cancelled"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"timestamp":{"description":"date and time the hold was last updated"},"itemtype":{"description":"If record level hold, the optional itemtype of the item the patron is requesting","type":["string","null"]},"suspend":{"description":""}},"type":"object"}},"paths":{"\/holds":{"post":{"tags":["borrowers","holds"],"operationId":"addHold","parameters":[{"description":"A JSON object containing informations about the new hold","schema":{"properties":{"itemnumber":{"type":"integer","description":"Item internal identifier"},"expirationdate":{"format":"date","type":"string","description":"Hold end date"},"borrowernumber":{"type":"integer","description":"Borrower internal identifier"},"biblionumber":{"type":"integer","description":"Biblio internal identifier"},"branchcode":{"type":"string","description":"Pickup location"}},"type":"object"},"name":"body","required":true,"in":"body"}],"consumes":["application\/json"],"responses":{"201":{"description":"Created hold","schema":{"type":"object","properties":{"suspend_until":{"description":""},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reservedate":{"description":"the date the hold was placed"},"reservenotes":{"description":"notes related to this hold"},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"lowestPriority":{"description":""},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"notificationdate":{"description":"currently unused"},"expirationdate":{"description":"the date the hold expires"},"reminderdate":{"description":"currently unused"},"priority":{"description":"where in the queue the patron sits"},"reserve_id":{"description":"Internal hold identifier"},"cancellationdate":{"description":"the date the hold was cancelled"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"timestamp":{"description":"date and time the hold was last updated"},"itemtype":{"description":"If record level hold, the optional itemtype of the item the patron is requesting","type":["string","null"]},"suspend":{"description":""}}}},"403":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Hold not allowed"},"500":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Internal error"},"400":{"description":"Missing or wrong parameters","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}},"404":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Borrower not found"}},"produces":["application\/json"]},"get":{"responses":{"200":{"description":"A list of holds","schema":{"type":"array","items":{"properties":{"suspend_until":{"description":""},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reservedate":{"description":"the date the hold was placed"},"reservenotes":{"description":"notes related to this hold"},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"lowestPriority":{"description":""},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"notificationdate":{"description":"currently unused"},"expirationdate":{"description":"the date the hold expires"},"reminderdate":{"description":"currently unused"},"priority":{"description":"where in the queue the patron sits"},"reserve_id":{"description":"Internal hold identifier"},"cancellationdate":{"description":"the date the hold was cancelled"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"timestamp":{"description":"date and time the hold was last updated"},"itemtype":{"description":"If record level hold, the optional itemtype of the item the patron is requesting","type":["string","null"]},"suspend":{"description":""}},"type":"object"}}},"404":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Borrower not found"}},"produces":["application\/json"],"parameters":[{"in":"query","name":"reserve_id","type":"integer","description":"Internal reserve identifier"},{"in":"query","description":"Internal borrower identifier","type":"integer","name":"borrowernumber"},{"type":"string","name":"reservedate","description":"Reserve date","in":"query"},{"in":"query","name":"biblionumber","type":"integer","description":"Internal biblio identifier"},{"description":"Branch code","name":"branchcode","type":"string","in":"query"},{"type":"string","name":"notificationdate","description":"Notification date","in":"query"},{"in":"query","name":"reminderdate","type":"string","description":"Reminder date"},{"in":"query","description":"Cancellation date","name":"cancellationdate","type":"string"},{"description":"Reserve notes","type":"string","name":"reservenotes","in":"query"},{"type":"integer","name":"priority","description":"Priority","in":"query"},{"description":"Found status","type":"string","name":"found","in":"query"},{"in":"query","description":"Time of latest update","name":"timestamp","type":"string"},{"in":"query","name":"itemnumber","type":"integer","description":"Internal item identifier"},{"in":"query","type":"string","name":"waitingdate","description":"Date the item was marked as waiting for the patron"},{"description":"Date the hold expires","name":"expirationdate","type":"string","in":"query"},{"description":"Lowest priority","name":"lowestPriority","type":"integer","in":"query"},{"in":"query","type":"integer","name":"suspend","description":"Suspended"},{"in":"query","description":"Suspended until","name":"suspend_until","type":"string"}],"operationId":"listHolds","tags":["borrowers","holds"]}},"\/patrons\/{borrowernumber}":{"get":{"parameters":[{"description":"Internal patron identifier","type":"integer","name":"borrowernumber","in":"path","required":true}],"produces":["application\/json"],"responses":{"404":{"description":"Patron not found","schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"}},"200":{"description":"A patron","schema":{"type":"object","properties":{"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"B_phone":{"description":"phone number for patron's alternate address","type":["string","null"]},"altcontactfirstname":{"description":"first name of alternate contact for the patron","type":["string","null"]},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"address":{"type":"string","description":"first address line of patron's primary address"},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"smsalertnumber":{"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)","type":["string","null"]},"password":{"type":["string","null"],"description":"patron's encrypted password"},"borrowernumber":{"description":"internally assigned user identifier","type":"string"},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"initials":{"type":["string","null"],"description":"initials of the patron"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"B_country":{"type":["string","null"],"description":"country of patron's alternate address"},"updated_on":{"type":"string","description":"time of last change could be useful for synchronization with external systems (among others)"},"city":{"type":"string","description":"city or town of patron's primary address"},"userid":{"description":"patron's login","type":["string","null"]},"debarred":{"type":["string","null"],"description":"until this date the patron can only check-in"},"lost":{"description":"set to 1 if library marked this patron as having lost his card","type":["string","null"]},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"debarredcomment":{"description":"comment on the stop of the patron","type":["string","null"]},"country":{"type":["string","null"],"description":"country of patron's primary address"},"sex":{"type":["string","null"],"description":"patron's gender"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"categorycode":{"description":"code of patron's category","type":"string"},"contacttitle":{"type":["string","null"],"description":"used for children to include title of guarantor"},"surname":{"type":"string","description":"patron's last name"},"altcontactcountry":{"type":["string","null"],"description":"the country for the alternate contact for the patron"},"title":{"type":["string","null"],"description":"patron's title"},"contactnote":{"type":["string","null"],"description":"a note related to patron's alternate address"},"sms_provider_id":{"type":["string","null"],"description":"the provider of the mobile phone number defined in smsalertnumber"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"altcontactaddress3":{"description":"the city for the alternate contact for the patron","type":["string","null"]},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"mobile":{"type":["string","null"],"description":"the other phone number for patron's primary address"},"B_address":{"type":["string","null"],"description":"first address line of patron's alternate address"},"email":{"type":["string","null"],"description":"primary email address for patron's primary address"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"B_zipcode":{"type":["string","null"],"description":"zip or postal code of patron's alternate address"},"dateofbirth":{"type":["string","null"],"description":"patron's date of birth"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"phonepro":{"description":"secondary phone number for patron's primary address","type":["string","null"]},"dateenrolled":{"description":"date the patron was added to Koha","type":["string","null"]},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"state":{"type":["string","null"],"description":"state or province of patron's primary address"},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"checkprevcheckout":{"description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'","type":"string"},"sort2":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"B_streetnumber":{"type":["string","null"],"description":"street number of patron's alternate address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"sort1":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"}}}},"403":{"description":"Access forbidden","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}}},"operationId":"getPatron","tags":["patrons"]}},"\/accountlines":{"get":{"tags":["accountlines"],"operationId":"listAccountlines","responses":{"403":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Access forbidden"},"200":{"schema":{"items":{"type":"object","properties":{"meansofpayment":{"description":"Means of payment"},"date":{"description":"Date when the account line was created"},"note":{"description":"Accountline note"},"amount":{"description":"Amount"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"accountlines_id":{"description":"Internal account line identifier"},"time":{"description":"Time when the account line was created"},"lastincrement":{"description":"?"},"accountno":{"description":"?"},"itemnumber":{"description":"Internal item identifier"},"amountoutstanding":{"description":"Amount outstanding"},"notify_level":{"description":"?"},"notify_id":{"description":"?"},"borrowernumber":{"description":"Internal borrower identifier"},"timestamp":{"description":"When the account line was last updated"},"description":{"description":"Description of account line"},"accounttype":{"description":"Type of accountline"}}},"type":"array"},"description":"A list of accountlines"}},"produces":["application\/json"]}},"\/accountlines\/{accountlines_id}\/payment":{"post":{"operationId":"payAccountlines","tags":["accountlines"],"consumes":["application\/json"],"parameters":[{"type":"integer","name":"accountlines_id","description":"Internal accountline identifier","in":"path","required":true},{"description":"A JSON object containing fields to modify","schema":{"properties":{"note":{"description":"Payment note"},"amount":{"description":"Amount to pay"}},"type":"object"},"name":"body","in":"body"}],"produces":["application\/json"],"responses":{"400":{"description":"Missing or wrong parameters","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}},"404":{"description":"Accountline not found","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}},"200":{"description":"Paid accountline","schema":{"type":"object","properties":{"meansofpayment":{"description":"Means of payment"},"date":{"description":"Date when the account line was created"},"note":{"description":"Accountline note"},"amount":{"description":"Amount"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"accountlines_id":{"description":"Internal account line identifier"},"time":{"description":"Time when the account line was created"},"lastincrement":{"description":"?"},"accountno":{"description":"?"},"itemnumber":{"description":"Internal item identifier"},"amountoutstanding":{"description":"Amount outstanding"},"notify_level":{"description":"?"},"notify_id":{"description":"?"},"borrowernumber":{"description":"Internal borrower identifier"},"timestamp":{"description":"When the account line was last updated"},"description":{"description":"Description of account line"},"accounttype":{"description":"Type of accountline"}}}},"403":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Access forbidden"}}}},"\/holds\/{reserve_id}":{"put":{"operationId":"editHold","tags":["holds"],"produces":["application\/json"],"responses":{"200":{"schema":{"type":"object","properties":{"suspend_until":{"description":""},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reservedate":{"description":"the date the hold was placed"},"reservenotes":{"description":"notes related to this hold"},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"lowestPriority":{"description":""},"waitingdate":{"description":"the date the item was marked as waiting for the patron at the library"},"found":{"description":"a one letter code defining what the status of the hold is after it has been confirmed"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"notificationdate":{"description":"currently unused"},"expirationdate":{"description":"the date the hold expires"},"reminderdate":{"description":"currently unused"},"priority":{"description":"where in the queue the patron sits"},"reserve_id":{"description":"Internal hold identifier"},"cancellationdate":{"description":"the date the hold was cancelled"},"borrowernumber":{"type":"string","description":"internally assigned user identifier"},"timestamp":{"description":"date and time the hold was last updated"},"itemtype":{"description":"If record level hold, the optional itemtype of the item the patron is requesting","type":["string","null"]},"suspend":{"description":""}}},"description":"Updated hold"},"404":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Hold not found"},"400":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Missing or wrong parameters"}},"parameters":[{"required":true,"in":"path","description":"Internal hold identifier","type":"integer","name":"reserve_id"},{"schema":{"type":"object","properties":{"branchcode":{"type":"string","description":"Pickup location"},"priority":{"description":"Position in waiting queue","type":"integer","minimum":1},"suspend_until":{"format":"date","description":"Suspend until","type":"string"}}},"description":"A JSON object containing fields to modify","name":"body","in":"body","required":true}],"consumes":["application\/json"]},"delete":{"responses":{"200":{"description":"Successful deletion","schema":{"type":"object"}},"404":{"description":"Hold not found","schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"}}},"produces":["application\/json"],"parameters":[{"description":"Internal hold identifier","type":"integer","name":"reserve_id","required":true,"in":"path"}],"tags":["holds"],"operationId":"deleteHold"}},"\/patrons":{"get":{"operationId":"listPatrons","tags":["patrons"],"produces":["application\/json"],"responses":{"200":{"description":"A list of patrons","schema":{"type":"array","items":{"properties":{"altcontactaddress1":{"description":"the first address line for the alternate contact for the patron","type":["string","null"]},"B_phone":{"description":"phone number for patron's alternate address","type":["string","null"]},"altcontactfirstname":{"description":"first name of alternate contact for the patron","type":["string","null"]},"relationship":{"type":["string","null"],"description":"used for children to include the relationship to their guarantor"},"address":{"type":"string","description":"first address line of patron's primary address"},"othernames":{"type":["string","null"],"description":"any other names associated with the patron"},"smsalertnumber":{"description":"the mobile phone number where the patron would like to receive notices (if SMS turned on)","type":["string","null"]},"password":{"type":["string","null"],"description":"patron's encrypted password"},"borrowernumber":{"description":"internally assigned user identifier","type":"string"},"altcontactzipcode":{"type":["string","null"],"description":"the zipcode for the alternate contact for the patron"},"initials":{"type":["string","null"],"description":"initials of the patron"},"borrowernotes":{"type":["string","null"],"description":"a note on the patron's account"},"B_country":{"type":["string","null"],"description":"country of patron's alternate address"},"updated_on":{"type":"string","description":"time of last change could be useful for synchronization with external systems (among others)"},"city":{"type":"string","description":"city or town of patron's primary address"},"userid":{"description":"patron's login","type":["string","null"]},"debarred":{"type":["string","null"],"description":"until this date the patron can only check-in"},"lost":{"description":"set to 1 if library marked this patron as having lost his card","type":["string","null"]},"guarantorid":{"description":"borrowernumber used for children or professionals to link them to guarantor or organizations","type":["string","null"]},"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"debarredcomment":{"description":"comment on the stop of the patron","type":["string","null"]},"country":{"type":["string","null"],"description":"country of patron's primary address"},"sex":{"type":["string","null"],"description":"patron's gender"},"opacnote":{"description":"a note on the patron's account visible in OPAC and staff client","type":["string","null"]},"altcontactphone":{"description":"the phone number for the alternate contact for the patron","type":["string","null"]},"emailpro":{"type":["string","null"],"description":"secondary email address for patron's primary address"},"B_address2":{"type":["string","null"],"description":"second address line of patron's alternate address"},"branchcode":{"type":["string","null"],"description":"code of patron's home branch"},"altcontactsurname":{"type":["string","null"],"description":"surname or last name of the alternate contact for the patron"},"B_email":{"description":"email address for patron's alternate address","type":["string","null"]},"categorycode":{"description":"code of patron's category","type":"string"},"contacttitle":{"type":["string","null"],"description":"used for children to include title of guarantor"},"surname":{"type":"string","description":"patron's last name"},"altcontactcountry":{"type":["string","null"],"description":"the country for the alternate contact for the patron"},"title":{"type":["string","null"],"description":"patron's title"},"contactnote":{"type":["string","null"],"description":"a note related to patron's alternate address"},"sms_provider_id":{"type":["string","null"],"description":"the provider of the mobile phone number defined in smsalertnumber"},"B_city":{"description":"city or town of patron's alternate address","type":["string","null"]},"fax":{"description":"fax number for patron's primary address","type":["string","null"]},"B_state":{"description":"state or province of patron's alternate address","type":["string","null"]},"altcontactaddress3":{"description":"the city for the alternate contact for the patron","type":["string","null"]},"firstname":{"description":"patron's first name","type":["string","null"]},"altcontactaddress2":{"type":["string","null"],"description":"the second address line for the alternate contact for the patron"},"mobile":{"type":["string","null"],"description":"the other phone number for patron's primary address"},"B_address":{"type":["string","null"],"description":"first address line of patron's alternate address"},"email":{"type":["string","null"],"description":"primary email address for patron's primary address"},"altcontactstate":{"type":["string","null"],"description":"the state for the alternate contact for the patron"},"privacy_guarantor_checkouts":{"description":"controls if relatives can see this patron's checkouts","type":"string"},"dateexpiry":{"type":["string","null"],"description":"date the patron's card is set to expire"},"B_zipcode":{"type":["string","null"],"description":"zip or postal code of patron's alternate address"},"dateofbirth":{"type":["string","null"],"description":"patron's date of birth"},"gonenoaddress":{"description":"set to 1 if library marked this patron as having an unconfirmed address","type":["string","null"]},"phonepro":{"description":"secondary phone number for patron's primary address","type":["string","null"]},"dateenrolled":{"description":"date the patron was added to Koha","type":["string","null"]},"contactfirstname":{"type":["string","null"],"description":"used for children to include first name of guarantor"},"privacy":{"type":"string","description":"patron's privacy settings related to their reading history"},"address2":{"type":["string","null"],"description":"second address line of patron's primary address"},"state":{"type":["string","null"],"description":"state or province of patron's primary address"},"flags":{"type":["string","null"],"description":"a number associated with the patron's permissions"},"streetnumber":{"type":["string","null"],"description":"street number of patron's primary address"},"zipcode":{"type":["string","null"],"description":"zip or postal code of patron's primary address"},"checkprevcheckout":{"description":"produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'","type":"string"},"sort2":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"},"cardnumber":{"type":["string","null"],"description":"library assigned user identifier"},"streettype":{"type":["string","null"],"description":"street type of patron's primary address"},"B_streetnumber":{"type":["string","null"],"description":"street number of patron's alternate address"},"contactname":{"type":["string","null"],"description":"used for children and professionals to include surname or last name of guarantor or organization name"},"B_streettype":{"description":"street type of patron's alternate address","type":["string","null"]},"sort1":{"type":["string","null"],"description":"a field that can be used for any information unique to the library"}},"type":"object"}}},"403":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Access forbidden"}}}},"\/accountlines\/{accountlines_id}":{"put":{"parameters":[{"type":"integer","name":"accountlines_id","description":"Internal accountline identifier","in":"path","required":true},{"in":"body","required":true,"name":"body","schema":{"properties":{"amountoutstanding":{"description":"Amount outstanding"},"amount":{"description":"Amount"},"meansofpayment":{"description":"Means of payment"},"note":{"description":"Accountline note"}},"type":"object"},"description":"A JSON object containing fields to modify"}],"consumes":["application\/json"],"produces":["application\/json"],"responses":{"403":{"description":"Access forbidden","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}},"400":{"description":"Missing or wrong parameters","schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"}},"404":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Accountline not found"},"200":{"schema":{"properties":{"meansofpayment":{"description":"Means of payment"},"date":{"description":"Date when the account line was created"},"note":{"description":"Accountline note"},"amount":{"description":"Amount"},"manager_id":{"description":"Borrowernumber of user that created the account line"},"accountlines_id":{"description":"Internal account line identifier"},"time":{"description":"Time when the account line was created"},"lastincrement":{"description":"?"},"accountno":{"description":"?"},"itemnumber":{"description":"Internal item identifier"},"amountoutstanding":{"description":"Amount outstanding"},"notify_level":{"description":"?"},"notify_id":{"description":"?"},"borrowernumber":{"description":"Internal borrower identifier"},"timestamp":{"description":"When the account line was last updated"},"description":{"description":"Description of account line"},"accounttype":{"description":"Type of accountline"}},"type":"object"},"description":"Updated accountline"}},"tags":["accountlines"],"operationId":"editAccountlines"}},"\/patrons\/{borrowernumber}\/payment":{"post":{"parameters":[{"in":"path","required":true,"description":"Internal patron identifier","type":"integer","name":"borrowernumber"},{"schema":{"properties":{"note":{"description":"Payment note"},"amount":{"description":"Amount to pay"}},"type":"object"},"description":"A JSON object containing fields to modify","name":"body","in":"body","required":true}],"consumes":["application\/json"],"responses":{"400":{"schema":{"properties":{"error":{"description":"Error message","type":"string"}},"type":"object"},"description":"Missing or wrong parameters"},"404":{"schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}},"description":"Borrower not found"},"204":{"description":"Success"},"403":{"description":"Access forbidden","schema":{"type":"object","properties":{"error":{"description":"Error message","type":"string"}}}}},"produces":["application\/json"],"operationId":"payForPatron","tags":["accountlines"]}}},"x-primitives":{"phone":{"description":"primary phone number for patron's primary address","type":["string","null"]},"itemnumber":{"type":["string","null"],"description":"internally assigned item identifier"},"email":{"type":["string","null"],"description":"primary email address for patron's primary address"},"surname":{"type":"string","description":"patron's last name"},"biblionumber":{"description":"internally assigned biblio identifier","type":"string"},"borrowernumber":{"description":"internally assigned user identifier","type":"string"},"cardnumber":{"description":"library assigned user identifier","type":["string","null"]},"firstname":{"description":"patron's first name","type":["string","null"]},"branchcode":{"description":"code of patron's home branch","type":["string","null"]},"reserve_id":{"description":"Internal hold identifier"}},"basePath":"\/api\/v1"} \ No newline at end of file diff --git a/t/db_dependent/api/v1/accountlines.t b/t/db_dependent/api/v1/accountlines.t index d2289e0..9eae405 100644 --- a/t/db_dependent/api/v1/accountlines.t +++ b/t/db_dependent/api/v1/accountlines.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 18; +use Test::More tests => 33; use Test::Mojo; use t::lib::TestBuilder; @@ -45,6 +45,9 @@ $t->get_ok('/api/v1/accountlines') $t->put_ok("/api/v1/accountlines/11224409" => json => {'amount' => -5}) ->status_is(403); +$t->post_ok("/api/v1/accountlines/11224408/payment") + ->status_is(403); + my $loggedinuser = $builder->build({ source => 'Borrower', value => { @@ -74,8 +77,8 @@ my $borrowernumber2 = $borrower2->{borrowernumber}; $dbh->do(q| DELETE FROM accountlines |); $dbh->do(q| - INSERT INTO accountlines (borrowernumber, amount, accounttype) - VALUES (?, 20, 'A'), (?, 40, 'F'), (?, 80, 'F'), (?, 10, 'F') + INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding) + VALUES (?, 20, 'A', 20), (?, 40, 'F', 40), (?, 80, 'F', 80), (?, 10, 'F', 10) |, undef, $borrowernumber, $borrowernumber, $borrowernumber, $borrowernumber2); my $session = C4::Auth::get_session(''); @@ -114,7 +117,6 @@ my $put_data = { $tx = $t->ua->build_tx( PUT => "/api/v1/accountlines/11224409" - => {Accept => '*/*'} => json => $put_data); $tx->req->cookies({name => 'CGISESSID', value => $session->id}); $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); @@ -125,7 +127,6 @@ my $accountline_to_edit = Koha::Account::Lines->search({'borrowernumber' => $bor $tx = $t->ua->build_tx( PUT => "/api/v1/accountlines/$accountline_to_edit->{accountlines_id}" - => {Accept => '*/*'} => json => $put_data); $tx->req->cookies({name => 'CGISESSID', value => $session->id}); $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); @@ -139,5 +140,55 @@ is($accountline_edited->{amountoutstanding}, '-19.000000'); # Payment tests +$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/4562765765/payment"); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(404); + +my $accountline_to_pay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 20})->unblessed()->[0]; +$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_pay->{accountlines_id}/payment"); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(200); +#$t->content_is('toto'); + +my $accountline_paid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => -20})->unblessed()->[0]; +ok($accountline_paid); + +# Partial payment tests +my $post_data = { + 'amount' => 17, + 'note' => 'Partial payment' +}; + +$tx = $t->ua->build_tx( + POST => "/api/v1/accountlines/11224419/payment" + => json => $post_data); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(404); + +my $accountline_to_partiallypay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0]; + +$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/payment" => json => {amount => 'foo'}); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(400); + +$tx = $t->ua->build_tx(POST => "/api/v1/accountlines/$accountline_to_partiallypay->{accountlines_id}/payment" => json => $post_data); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(200); + +$accountline_to_partiallypay = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => 80})->unblessed()->[0]; +is($accountline_to_partiallypay->{amountoutstanding}, '63.000000'); + +my $accountline_partiallypaid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber, 'amount' => -17})->unblessed()->[0]; +ok($accountline_partiallypaid); $dbh->rollback; diff --git a/t/db_dependent/api/v1/patrons.t b/t/db_dependent/api/v1/patrons.t index 6bd4e1a..2e8a3e6 100644 --- a/t/db_dependent/api/v1/patrons.t +++ b/t/db_dependent/api/v1/patrons.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 10; +use Test::More tests => 21; use Test::Mojo; use t::lib::TestBuilder; @@ -26,6 +26,7 @@ use C4::Context; use Koha::Database; use Koha::Patron; +use Koha::Account::Lines; my $builder = t::lib::TestBuilder->new(); @@ -50,6 +51,7 @@ $t->get_ok('/api/v1/patrons') ->status_is(403); $t->get_ok("/api/v1/patrons/" . $borrower->{ borrowernumber }) + ->status_is(403); my $loggedinuser = $builder->build({ @@ -57,7 +59,7 @@ my $loggedinuser = $builder->build({ value => { branchcode => $branchcode, categorycode => $categorycode, - flags => 16 # borrowers flag + flags => 1040 # borrowers and updatecharges (2^4 | 2^10) } }); @@ -81,4 +83,56 @@ $t->request_ok($tx) ->json_is('/borrowernumber' => $borrower->{ borrowernumber }) ->json_is('/surname' => $borrower->{ surname }); + +# Payment tests +my $borrower2 = $builder->build({ + source => 'Borrower', + value => { + branchcode => $branchcode, + categorycode => $categorycode, + } +}); +my $borrowernumber2 = $borrower2->{borrowernumber}; + +$dbh->do(q| + INSERT INTO accountlines (borrowernumber, amount, accounttype, amountoutstanding) + VALUES (?, 26, 'A', 26) + |, undef, $borrowernumber2); + +$t->post_ok("/api/v1/patrons/$borrowernumber2/payment" => json => {'amount' => 8}) + ->status_is(403); + +my $post_data2 = { + 'amount' => 24, + 'note' => 'Partial payment' +}; + +$tx = $t->ua->build_tx(POST => "/api/v1/patrons/8789798797/payment" => json => $post_data2); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(404); + +$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => {amount => 0}); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(400); + +$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => {amount => 'foo'}); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(400); + +$tx = $t->ua->build_tx(POST => "/api/v1/patrons/$borrowernumber2/payment" => json => $post_data2); +$tx->req->cookies({name => 'CGISESSID', value => $session->id}); +$tx->req->env({REMOTE_ADDR => '127.0.0.1'}); +$t->request_ok($tx) + ->status_is(204); + +my $accountline_partiallypaid = Koha::Account::Lines->search({'borrowernumber' => $borrowernumber2, 'amount' => 26})->unblessed()->[0]; + +is($accountline_partiallypaid->{amountoutstanding}, '2.000000'); + $dbh->rollback; -- 2.1.4