Commits (2)
......@@ -30,6 +30,8 @@ use C4::Stats qw( UpdateStats );
use C4::Overdues qw(GetFine);
use Koha::Patrons;
use Koha::Account::Credits;
use Koha::Account::Debits;
use Koha::Account::Lines;
use Koha::Account::Offsets;
use Koha::Account::DebitTypes;
......@@ -738,6 +740,43 @@ sub lines {
);
}
=head3 credits
my $credits = $self->credits;
Return all credits for the user
=cut
sub credits {
my ($self) = @_;
return Koha::Account::Credits->search(
{
borrowernumber => $self->{patron_id}
}
);
}
=head3 debits
my $debits = $self->debits;
Return all debits for the user
=cut
sub debits {
my ($self) = @_;
return Koha::Account::Debits->search(
{
borrowernumber => $self->{patron_id},
}
);
}
=head3 reconcile_balance
$account->reconcile_balance();
......
package Koha::Account::Credit;
# Copyright PTFS Europe 2021
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use base qw(Koha::Account::Line);
=head1 NAME
Koha::Credit - Koha Credit object class
This object represents a credit account line
=head1 API
=head2 Class Methods
=head3 to_api_mapping
This method returns the mapping for representing a Koha::Account::Credit object
on the API.
=cut
sub to_api_mapping {
return {
accountlines_id => 'account_line_id',
credit_number => undef,
credit_type_code => 'credit_type',
debit_type_code => undef,
amountoutstanding => 'amount_outstanding',
borrowernumber => 'patron_id',
branchcode => 'library_id',
issue_id => 'checkout_id',
itemnumber => 'item_id',
manager_id => 'user_id',
note => 'internal_note',
register_id => 'cash_register_id',
};
}
=head1 AUTHOR
Martin Renvoize <martin.renvoize@ptfs-europe.com>
=cut
1;
package Koha::Account::Credits;
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Koha::Database;
use Koha::Account::Credit;
use base qw(Koha::Account::Lines);
=head1 NAME
Koha::Account::Credits - Koha Cash Register Action Object set class
=head1 API
=head2 Class methods
=head3 search
my $credits = Koha::Account::Credits->search( $where, $attr );
Returns a list of credit lines.
=cut
sub search {
my ( $self, $where, $attr ) = @_;
my $rs = $self->SUPER::search({ debit_type_code => undef });
return $rs->SUPER::search( $where, $attr );
}
=head3 object_class
=cut
sub object_class {
return 'Koha::Account::Credit';
}
1;
package Koha::Account::Debit;
# Copyright PTFS Europe 2021
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use base qw(Koha::Account::Line);
=head1 NAME
Koha::Debit - Koha Debit object class
This object represents a debit account line
=head1 API
=head2 Class Methods
=head3 to_api_mapping
This method returns the mapping for representing a Koha::Account::Debit object
on the API.
=cut
sub to_api_mapping {
return {
accountlines_id => 'account_line_id',
credit_number => undef,
credit_type_code => undef,
debit_type_code => 'debit_type',
amountoutstanding => 'amount_outstanding',
borrowernumber => 'patron_id',
branchcode => 'library_id',
issue_id => 'checkout_id',
itemnumber => 'item_id',
manager_id => 'user_id',
note => 'internal_note',
register_id => 'cash_register_id',
payment_type => undef
};
}
=head1 AUTHOR
Martin Renvoize <martin.renvoize@ptfs-europe.com>
=cut
1;
package Koha::Account::Debits;
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Koha::Database;
use Koha::Account::Debit;
use base qw(Koha::Account::Lines);
=head1 NAME
Koha::Account::Debits - Koha Cash Register Action Object set class
=head1 API
=head2 Class methods
=head3 search
my $debits = Koha::Account::Debits->search( $where, $attr );
Returns a list of debit lines.
=cut
sub search {
my ( $self, $where, $attr ) = @_;
my $rs = $self->SUPER::search({ credit_type_code => undef });
return $rs->SUPER::search( $where, $attr );
}
=head3 object_class
=cut
sub object_class {
return 'Koha::Account::Debit';
}
1;
......@@ -74,6 +74,32 @@ sub get {
};
}
=head3 list_credits
=cut
sub list_credits {
my $c = shift->openapi->valid_input or return;
my $patron_id = $c->validation->param('patron_id');
my $patron = Koha::Patrons->find($patron_id);
unless ($patron) {
return $c->render( status => 404, openapi => { error => "Patron not found." } );
}
return try {
my $account = $patron->account;
my $credits_set = $account->credits;
my $credits = $c->objects->search( $credits_set );
return $c->render( status => 200, openapi => $credits );
}
catch {
$c->unhandled_exception($_);
};
}
=head3 add_credit
Controller function that handles adding a credit to a patron's account
......@@ -153,4 +179,30 @@ sub add_credit {
};
}
=head3 list_debits
=cut
sub list_debits {
my $c = shift->openapi->valid_input or return;
my $patron_id = $c->validation->param('patron_id');
my $patron = Koha::Patrons->find($patron_id);
unless ($patron) {
return $c->render( status => 404, openapi => { error => "Patron not found." } );
}
return try {
my $account = $patron->account;
my $debits_set = $account->debits;
my $debits = $c->objects->search( $debits_set );
return $c->render( status => 200, openapi => $debits );
}
catch {
$c->unhandled_exception($_);
};
}
1;
......@@ -17,6 +17,10 @@ circ-rule-kind:
$ref: definitions/circ-rule-kind.yaml
city:
$ref: definitions/city.yaml
credit:
$ref: definitions/credit.yaml
debit:
$ref: definitions/debit.yaml
error:
$ref: definitions/error.yaml
fund:
......
---
type: object
properties:
account_line_id:
type:
- integer
- "null"
readOnly: true
description: Internal account line identifier
amount:
type: number
minimum: 0
description: Credit amount
amount_outstanding:
type: number
readOnly: true
description: Outstanding amount
cash_register_id:
type:
- integer
- "null"
description: Internal identifier for the cash register used for the payment (if any)
checkout_id:
type:
- integer
- "null"
description: Internal identifier for the checkout the account line is related to
credit_type:
type:
- string
- "null"
description: Account line credit type
date:
type: string
format: date-time
readOnly: true
description: Date the account line was created
description:
type:
- string
- "null"
readOnly: true
description: Account line description
interface:
type:
- string
- "null"
description: 'Interface in which the account line was generated (values can be: api, cron, commandline, intranet, opac and sip)'
internal_note:
type:
- string
- "null"
description: Internal note
item_id:
type:
- integer
- "null"
description: Internal identifier for the item the account line is related to
library_id:
type:
- string
- "null"
description: Internal identifier for the library in which the transaction took place
patron_id:
type: integer
readOnly: true
description: Internal identifier for the patron the account line belongs to
payment_type:
type:
- string
- "null"
description: Payment type
status:
type:
- string
- "null"
readOnly: true
description: The credit/debit status
timestamp:
type: string
format: date-time
readOnly: true
description: Timestamp for the latest line update
user_id:
type:
- integer
- "null"
description: Internal patron identifier for the staff member that introduced the account line
required:
- amount
additionalProperties: false
type: object
properties:
account_line_id:
type:
- integer
- "null"
readOnly: true
description: Internal account line identifier
checkout_id:
type:
- integer
- "null"
description: Internal identifier for the checkout the account line is related to
patron_id:
type: integer
readOnly: true
description: Internal identifier for the patron the account line belongs to
item_id:
type:
- integer
- "null"
description: Internal identifier for the item the account line is related to
date:
type: string
format: date-time
readOnly: true
description: Date the account line was created
amount:
type: number
description: Account line amount
description:
type:
- string
- "null"
readOnly: true
description: Account line description
account_type:
type:
- string
- "null"
description: Account line type
debit_type:
type:
- string
- "null"
description: Account line debit type
payout_type:
type:
- string
- "null"
description: Payout type
amount_outstanding:
type: number
readOnly: true
description: Outstanding amount
timestamp:
type: string
format: date-time
readOnly: true
description: Timestamp for the latest line update
internal_note:
type:
- string
- "null"
description: Internal note
user_id:
type:
- integer
- "null"
description: Internal patron identifier for the staff member that introduced the account line
library_id:
type:
- string
- "null"
description: Internal identifier for the library in which the transaction took place
interface:
type:
- string
- "null"
description: 'Interface in which the account line was generated (values can be: api, cron, commandline, intranet, opac and sip)'
status:
type:
- string
- "null"
readOnly: true
description: The credit/debit status
cash_register_id:
type:
- integer
- "null"
description: Internal identifier for the cash register used for the payment (if any)
required:
- amount
additionalProperties: false
......@@ -89,6 +89,8 @@
$ref: paths/patrons_account.yaml#/~1patrons~1{patron_id}~1account
"/patrons/{patron_id}/account/credits":
$ref: paths/patrons_account.yaml#/~1patrons~1{patron_id}~1account~1credits
"/patrons/{patron_id}/account/debits":
$ref: paths/patrons_account.yaml#/~1patrons~1{patron_id}~1account~1debits
"/patrons/{patron_id}/extended_attributes":
$ref: paths/patrons_extended_attributes.yaml#/~1patrons~1{patron_id}~1extended_attributes
"/patrons/{patron_id}/extended_attributes/{extended_attribute_id}":
......
......@@ -43,6 +43,47 @@
borrowers: edit_borrowers
updatecharges: remaining_permissions
"/patrons/{patron_id}/account/credits":
get:
x-mojo-to: Patrons::Account#list_credits
operationId: listPatronCredits
tags:
- patrons
- credits
summary: List patron credits
produces:
- application/json
parameters:
- $ref: ../parameters.yaml#/patron_id_pp
- $ref: ../parameters.yaml#/match
- $ref: ../parameters.yaml#/order_by
- $ref: ../parameters.yaml#/page
- $ref: ../parameters.yaml#/per_page
- $ref: ../parameters.yaml#/q_param
- $ref: ../parameters.yaml#/q_body
- $ref: ../parameters.yaml#/q_header
responses:
"200":
description: A list of credits
schema:
type: array
items:
$ref: ../definitions.yaml#/credit
"403":
description: Access forbidden
schema:
$ref: ../definitions.yaml#/error
"500":
description: Internal error
schema:
$ref: ../definitions.yaml#/error
"503":
description: Under maintenance
schema:
$ref: ../definitions.yaml#/error
x-koha-authorization:
permissions:
borrowers: edit_borrowers
updatecharges: remaining_permissions
post:
x-mojo-to: Patrons::Account#add_credit
operationId: addPatronCredit
......@@ -90,3 +131,49 @@
x-koha-authorization:
permissions:
updatecharges: remaining_permissions
"/patrons/{patron_id}/account/debits":
get:
x-mojo-to: Patrons::Account#list_debits
operationId: listPatronDebits
tags:
- patrons
- debits
summary: List patron debits
produces:
- application/json
parameters:
- $ref: ../parameters.yaml#/patron_id_pp
- $ref: ../parameters.yaml#/match
- $ref: ../parameters.yaml#/order_by
- $ref: ../parameters.yaml#/page
- $ref: ../parameters.yaml#/per_page
- $ref: ../parameters.yaml#/q_param
- $ref: ../parameters.yaml#/q_body
- $ref: ../parameters.yaml#/q_header
responses:
"200":
description: A list of debits
schema:
type: array
items:
$ref: ../definitions.yaml#/debit
"403":
description: Access forbidden
schema:
$ref: ../definitions.yaml#/error
"404":
description: Patron not found
schema:
$ref: ../definitions.yaml#/error
"500":
description: Internal error
schema:
$ref: ../definitions.yaml#/error
"503":
description: Under maintenance
schema:
$ref: ../definitions.yaml#/error
x-koha-authorization:
permissions:
borrowers: edit_borrowers
updatecharges: remaining_permissions
......@@ -135,6 +135,11 @@
[% IF ( CAN_user_updatecharges_remaining_permissions ) %]
[% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% patron.borrowernumber | uri %]">Accounting</a></li>
[% END %]
[% IF ( CAN_user_updatecharges_remaining_permissions ) %]
[% IF ( finesview2 ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/accounts.pl?borrowernumber=[% patron.borrowernumber | uri %]">Accounts</a></li>
[% END %]
[% IF ( CAN_user_circulate_circulate_remaining_permissions ) %]
[% IF Koha.Preference("RoutingSerials") %][% IF ( routinglistview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/routing-lists.pl?borrowernumber=[% patron.borrowernumber | uri %]">Routing lists</a></li>[% END %]
[% END %]
......
[% USE raw %]
[% USE Asset %]
[% USE Koha %]
[% USE Branches %]
[% USE KohaDates %]
[% USE TablesSettings %]
[% USE AuthorisedValues %]
[% USE Price %]
[% USE Branches %]
[% USE Registers %]
[% SET footerjs = 1 %]
[% SET registers = Registers.all( filters => { current_branch => 1 } ) %]
[% PROCESS 'accounts.inc' %]
[% INCLUDE 'doc-head-open.inc' %]
<title>Account for [% INCLUDE 'patron-title.inc' no_html = 1 %] &rsaquo; Patrons &rsaquo; Koha</title>
[% INCLUDE 'doc-head-close.inc' %]
</head>
<body id="pat_accounts" class="pat">
[% INCLUDE 'header.inc' %]
[% INCLUDE 'patron-search.inc' %]
<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="/cgi-bin/koha/mainpage.pl">Home</a>
</li>
<li>
<a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>
</li>
<li>
<a href="#" aria-current="page">Account for [% INCLUDE 'patron-title.inc' %]</a>
</li>
</ol>
</nav>
<div class="main container-fluid">
<div class="row">
<div class="col-sm-10 col-sm-push-2">
[% INCLUDE 'members-toolbar.inc' %]
<main>
[% IF outstanding_credit %]
<h2>Outstanding credits</h2>
<table id="creditst"></table>
[% END %]
<h2>Charges</h2>
<table id="chargest"></table>
</main>
</div>
<!-- /.col-sm-10.col-sm-push-2 -->
<div class="col-sm-2 col-sm-pull-10">
<aside>
[% INCLUDE 'circ-menu.inc' %]
</aside>
</div>
<!-- /.col-sm-2.col-sm-pull-10 -->
</div>
<!-- /.row -->
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'datatables.inc' %]
[% INCLUDE 'columns_settings.inc' %]
[% INCLUDE 'js-date-format.inc' %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("js/members-menu.js") | $raw %]
<script>
$(document).ready(function() {
[% IF outstanding_credit %]
var credits_table_url = '/api/v1/patrons/[% patron.borrowernumber | uri %]/account/credits?';
var credits_table = $("#creditst").kohaTable({
"ajax": {
"url": credits_table_url
},
"embed": [
],
"order": [[ 0, "desc" ]],
"columns": [{
"data": "date",
"title": "Date",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return $date(row.date);
},
},
{
"name": "credit_type",
"title": "Type",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return escape_str(row.credit_type);
},
},
{
"name": "description",
"title": "Description",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return escape_str(row.description);
},
},
{
"name": "amount",
"title": "Amount",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
var amt = row.amount * -1;
return escape_price(amt);
},
},
{
"name": "amount_outstanding",
"title": "Outstanding",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
var amt = row.amount_outstanding * -1;
return escape_price(amt);
},
},
{
"name": "actions",
"title": "Actions",
"searchable": false,
"orderable": false,
"render": function(data,type,row,meta){
return "<button class='btn btn-default btn-xs'>Action 1</button>";
}
}]
}, {}, 1);
[% END %]
var charges_table_url = '/api/v1/patrons/[% patron.borrowernumber | uri %]/account/debits?';
var charges_table = $("#chargest").kohaTable({
"ajax": {
"url": charges_table_url
},
"embed": [
],
"order": [[ 0, "desc" ]],
"columns": [{
"data": "date",
"title": "Date",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return $date(row.date);
},
},
{
"name": "debit_type",
"title": "Type",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return escape_str(row.debit_type);
},
},
{
"name": "description",
"title": "Description",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
return escape_str(row.description);
},
},
{
"name": "amount",
"title": "Amount",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
var amt = row.amount * -1;
return escape_price(amt);
},
},
{
"name": "amount_outstanding",
"title": "Outstanding",
"searchable": true,
"orderable": true,
"render": function(data, type, row, meta) {
var amt = row.amount_outstanding * -1;
return escape_price(amt);
},
},
{
"name": "actions",
"title": "Actions",
"searchable": false,
"orderable": false,
"render": function(data,type,row,meta){
return "<button class='btn btn-default btn-xs'>Action 1</button>";
}
}]
}, {}, 1);
});
</script>
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]
#!/usr/bin/perl
# This file is part of Koha.
#
# Copyright 2017 ByWater Solutions
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use CGI qw ( -utf8 );
use C4::Auth qw( get_template_and_user );
use C4::Output qw( output_html_with_http_headers );
use C4::Context;
use Koha::Patrons;
use Koha::Account::Lines;
my $input = CGI->new;
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "members/accounts.tt",
query => $input,
type => "intranet",
flagsrequired => {
borrowers => 'edit_borrowers',
updatecharges => 'remaining_permissions'
},
}
);
my $borrowernumber = $input->param('borrowernumber');
my $patron = Koha::Patrons->find($borrowernumber);
my $account = $patron->account;
my $outstanding_credit = $account->outstanding_credits->total_outstanding;
my $outstanding_debit = $account->outstanding_debits->total_outstanding;
$template->param(
patron => $patron,
outstanding_credit => $outstanding_credit,
outstanding_debit => $outstanding_debit
);
# Outstanding credits if any exist
#
# Charges with outstanding at the top
# Charges shoudl allow expanding to display offset details
output_html_with_http_headers $input, $cookie, $template->output;