From 5576aebeed0553e4aebda5216aade61b76570d10 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Wed, 19 Aug 2020 08:34:35 +0100 Subject: [PATCH] Bug 26274: Add Cashups subclass and API classes --- Koha/Cash/Register/Cashup.pm | 166 +++++++++++++++++++ Koha/Cash/Register/Cashups.pm | 64 +++++++ Koha/REST/V1/CashRegisters/Cashups.pm | 75 +++++++++ api/v1/swagger/definitions.json | 3 + api/v1/swagger/definitions/cashup.json | 26 +++ api/v1/swagger/parameters.json | 6 + api/v1/swagger/parameters/cash_register.json | 9 + api/v1/swagger/parameters/cashup.json | 9 + api/v1/swagger/paths.json | 6 + api/v1/swagger/paths/cash_registers.json | 101 +++++++++++ 10 files changed, 465 insertions(+) create mode 100644 Koha/Cash/Register/Cashup.pm create mode 100644 Koha/Cash/Register/Cashups.pm create mode 100644 Koha/REST/V1/CashRegisters/Cashups.pm create mode 100644 api/v1/swagger/definitions/cashup.json create mode 100644 api/v1/swagger/parameters/cash_register.json create mode 100644 api/v1/swagger/parameters/cashup.json create mode 100644 api/v1/swagger/paths/cash_registers.json diff --git a/Koha/Cash/Register/Cashup.pm b/Koha/Cash/Register/Cashup.pm new file mode 100644 index 0000000000..3732763a4a --- /dev/null +++ b/Koha/Cash/Register/Cashup.pm @@ -0,0 +1,166 @@ +package Koha::Cash::Register::Cashup; + +# 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 . + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use base qw(Koha::Cash::Register::Action); + +=head1 NAME + +Koha::Cash::Register::Actions - Koha Cash Register Action Object set class + +=head1 API + +=head2 Class methods + +=head3 search + + my $cashup = Koha::Cash::Register::Actions::Cashup->search( $where, $attr ); + +Returns a list of cash register cashup. + +=cut + +sub search { + my ( $self, $where, $attr ) = @_; + + $where->{code} = 'CASHUP'; + + unless ( exists $attr->{order_by} ) { + $attr->{order_by} = + [ { '-asc' => 'register_id' }, { '-desc' => 'timestamp' } ]; + } + + return $self->SUPER::search( $where, $attr ); +} + +=head3 summary + + my $summary = $cashup->summary; + +Return a hashref containing a summary of transactions that make up this cashup. + +=cut + +sub summary { + my ($self) = @_; + my $summary; + my $prior_cashup = Koha::Cash::Register::Cashups->search( + { + 'timestamp' => { '<' => $self->timestamp }, + register_id => $self->register_id + }, + { + order_by => { '-desc' => [ 'timestamp', 'id' ] }, + rows => 1 + } + ); + + my $previous = $prior_cashup->single; + + my $conditions = + $previous + ? { + 'date' => { + '-between' => + [ $previous->_result->get_column('timestamp'), $self->timestamp ] + } + } + : { 'date' => { '<' => $self->timestamp } }; + + my $outgoing_transactions = $self->register->accountlines->search( + { %{$conditions}, credit_type_code => undef }, + ); + my $income_transactions = $self->register->accountlines->search( + { %{$conditions}, debit_type_code => undef }, + ); + + my $income_summary = Koha::Account::Offsets->search( + { + 'me.credit_id' => + { '-in' => $income_transactions->_resultset->get_column('accountlines_id')->as_query }, + 'me.debit_id' => { '!=' => undef } + }, + { + join => { 'debit' => 'debit_type_code' }, + group_by => [ 'debit.debit_type_code', 'debit_type_code.description' ], + 'select' => [ { sum => 'me.amount' }, 'debit.debit_type_code', 'debit_type_code.description' ], + 'as' => [ 'total', 'debit_type_code', 'debit_description' ], + } + ); + + my $outgoing_summary = Koha::Account::Offsets->search( + { + 'me.debit_id' => + { '-in' => $outgoing_transactions->_resultset->get_column('accountlines_id')->as_query }, + 'me.credit_id' => { '!=' => undef } + }, + { + join => { 'credit' => 'credit_type_code' }, + group_by => [ 'credit.credit_type_code', 'credit_type_code.description' ], + 'select' => [ { sum => 'me.amount' }, 'credit.credit_type_code', 'credit_type_code.description' ], + 'as' => [ 'total', 'credit_type_code', 'credit_description' ], + } + ); + + my @income = map { + { + total => $_->get_column('total'), + debit_type_code => $_->get_column('debit_type_code'), + debit_type => { description => $_->get_column('debit_description') } + } + } $income_summary->as_list; + my @outgoing = map { + { + total => $_->get_column('total'), + credit_type_code => $_->get_column('credit_type_code'), + credit_type => { description => $_->get_column('credit_description') } + } + } $outgoing_summary->as_list; + + $summary = { + from_date => $previous ? $previous->timestamp : undef, + to_date => $self->timestamp, + income => \@income, + outgoing => \@outgoing, + income_transactions => $income_transactions, + outgoing_transactions => $outgoing_transactions, + }; + + return $summary; +} + +=head3 to_api_mapping + +This method returns the mapping for representing a Koha::Cash::Regiser::Cashup object +on the API. + +=cut + +sub to_api_mapping { + return { + id => 'cashup_id', + register_id => 'cash_register_id', + code => undef + }; +} + +1; diff --git a/Koha/Cash/Register/Cashups.pm b/Koha/Cash/Register/Cashups.pm new file mode 100644 index 0000000000..9100f38266 --- /dev/null +++ b/Koha/Cash/Register/Cashups.pm @@ -0,0 +1,64 @@ +package Koha::Cash::Register::Cashups; + +# 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 . + +use Modern::Perl; + +use Carp; + +use Koha::Database; +use Koha::Cash::Register::Cashup; + +use base qw(Koha::Cash::Register::Actions); + +=head1 NAME + +Koha::Cash::Register::Actions - Koha Cash Register Action Object set class + +=head1 API + +=head2 Class methods + +=head3 search + + my $cashups = Koha::Cash::Register::Cashups->search( $where, $attr ); + +Returns a list of cash register cashups. + +=cut + +sub search { + my ( $self, $where, $attr ) = @_; + + $where->{code} = 'CASHUP'; + + unless ( exists $attr->{order_by} ) { + $attr->{order_by} = + [ { '-asc' => 'register_id' }, { '-desc' => 'timestamp' } ]; + } + + return $self->SUPER::search( $where, $attr ); +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::Cash::Register::Cashup'; +} + +1; diff --git a/Koha/REST/V1/CashRegisters/Cashups.pm b/Koha/REST/V1/CashRegisters/Cashups.pm new file mode 100644 index 0000000000..11ccd302bc --- /dev/null +++ b/Koha/REST/V1/CashRegisters/Cashups.pm @@ -0,0 +1,75 @@ +package Koha::REST::V1::CashRegisters::Cashups; + +# 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 . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Scalar::Util qw(blessed); +use Try::Tiny; + +use Koha::Cash::Register::Cashups; + +=head1 NAME + +Koha::REST::V1::CashRegisters::Cashups + +=head1 API + +=head2 Methods + +=head3 list + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $cashups_set = Koha::Cash::Register::Cashups->new; + my $cashups = $c->objects->search( $cashups_set ); + return $c->render( status => 200, openapi => $cashups ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 get + +Controller function that handles retrieving a cash register cashup + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + return try { + my $cashup = Koha::Cash::Register::Cashups->find( $c->validation->param('cashup_id') ); + unless ($cashup) { + return $c->render( status => 404, + openapi => { error => "Cashup not found" } ); + } + + return $c->render( status => 200, openapi => $cashup->to_api ); + } + catch { + $c->unhandled_exception($_); + } +} + +1; diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json index e35054a456..583b26ab88 100644 --- a/api/v1/swagger/definitions.json +++ b/api/v1/swagger/definitions.json @@ -5,6 +5,9 @@ "basket": { "$ref": "definitions/basket.json" }, + "cashup": { + "$ref": "definitions/cashup.json" + }, "circ-rule-kind": { "$ref": "definitions/circ-rule-kind.json" }, diff --git a/api/v1/swagger/definitions/cashup.json b/api/v1/swagger/definitions/cashup.json new file mode 100644 index 0000000000..ffcaa1c0a8 --- /dev/null +++ b/api/v1/swagger/definitions/cashup.json @@ -0,0 +1,26 @@ +{ + "type": "object", + "properties": { + "cashup_id": { + "type": "integer", + "description": "Internal cashup identifier" + }, + "cash_register_id": { + "type": "integer", + "description": "Internal identifier for the register the cashup belongs to" + }, + "manager_id": { + "type": "integer", + "description": "Internal identifier for the manager the cashup was performed by" + }, + "amount": { + "type": "number", + "description": "Account line amount" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp for the latest line update" + } + } +} diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json index ddced814d0..a9d3f6cc95 100644 --- a/api/v1/swagger/parameters.json +++ b/api/v1/swagger/parameters.json @@ -44,6 +44,12 @@ "seen_pp": { "$ref": "parameters/checkout.json#/seen_pp" }, + "cash_register_id_pp": { + "$ref": "parameters/cash_register.json#/cash_register_id_pp" + }, + "cashup_id_pp": { + "$ref": "parameters/cashup.json#/cashup_id_pp" + }, "match": { "name": "_match", "in": "query", diff --git a/api/v1/swagger/parameters/cash_register.json b/api/v1/swagger/parameters/cash_register.json new file mode 100644 index 0000000000..5d46cc94a1 --- /dev/null +++ b/api/v1/swagger/parameters/cash_register.json @@ -0,0 +1,9 @@ +{ + "cash_register_id_pp": { + "name": "cash_register_id", + "in": "path", + "description": "Cash register internal identifier", + "required": true, + "type": "integer" + } +} diff --git a/api/v1/swagger/parameters/cashup.json b/api/v1/swagger/parameters/cashup.json new file mode 100644 index 0000000000..c0c3883959 --- /dev/null +++ b/api/v1/swagger/parameters/cashup.json @@ -0,0 +1,9 @@ +{ + "cashup_id_pp": { + "name": "cashup_id", + "in": "path", + "description": "Cashup internal identifier", + "required": true, + "type": "integer" + } +} diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index 3b5dc352d5..793da85996 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -17,6 +17,12 @@ "/acquisitions/funds": { "$ref": "paths/acquisitions_funds.json#/~1acquisitions~1funds" }, + "/cash_registers/{cash_register_id}/cashups": { + "$ref": "paths/cash_registers.json#/~1cash_registers~1{cash_register_id}~1cashups" + }, + "/cashups/{cashup_id}": { + "$ref": "paths/cash_registers.json#/~1cashups~1{cashup_id}" + }, "/checkouts": { "$ref": "paths/checkouts.json#/~1checkouts" }, diff --git a/api/v1/swagger/paths/cash_registers.json b/api/v1/swagger/paths/cash_registers.json new file mode 100644 index 0000000000..b730c4afcc --- /dev/null +++ b/api/v1/swagger/paths/cash_registers.json @@ -0,0 +1,101 @@ +{ + "/cash_registers/{cash_register_id}/cashups": { + "get": { + "x-mojo-to": "CashRegisters::Cashups#list", + "operationId": "listCashups", + "tags": ["cash_registers", "cashups"], + "produces": ["application/json"], + "parameters": [{ + "$ref": "../parameters.json#/cash_register_id_pp" + }, + { + "$ref": "../parameters.json#/match" + }, + { + "$ref": "../parameters.json#/order_by" + }, + { + "$ref": "../parameters.json#/page" + }, + { + "$ref": "../parameters.json#/per_page" + }, + { + "$ref": "../parameters.json#/q_param" + }, + { + "$ref": "../parameters.json#/q_body" + }, + { + "$ref": "../parameters.json#/q_header" + } + ], + "responses": { + "200": { + "description": "Cashups performed on this register", + "schema": { + "type": "array", + "items": { + "$ref": "../definitions.json#/cashup" + } + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Register not found", + "schema": { + "$ref": "../definitions.json#/error" + } + } + }, + "x-koha-authorization": { + "permissions": { + "cash_management": "cashup" + } + } + } + }, + "/cashups/{cashup_id}": { + "get": { + "x-mojo-to": "CashRegisters::Cashups#get", + "operationId": "getCashup", + "tags": ["cash_registers", "cashups"], + "parameters": [{ + "$ref": "../parameters.json#/cashup_id_pp" + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A cashup", + "schema": { + "$ref": "../definitions.json#/cashup" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Patron not found", + "schema": { + "$ref": "../definitions.json#/error" + } + } + }, + "x-koha-authorization": { + "permissions": { + "cash_management": "cashup" + } + } + } + } +} -- 2.20.1