@@ -, +, @@ the screen. left. price of the item in the table on the left. collected from patron' box. appears here. back at a fresh 'Pay' page ready for the next transaction. --- Koha/Charges/Sales.pm | 285 ++++++++++++++++ installer/data/mysql/account_offset_types.sql | 1 + .../data/mysql/atomicupdate/bug_23354.perl | 10 + .../prog/en/includes/pos-menu.inc | 16 + .../prog/en/modules/intranet-main.tt | 4 + .../intranet-tmpl/prog/en/modules/pos/pay.tt | 319 ++++++++++++++++++ pos/pay.pl | 79 +++++ 7 files changed, 714 insertions(+) create mode 100644 Koha/Charges/Sales.pm create mode 100644 installer/data/mysql/atomicupdate/bug_23354.perl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/pos-menu.inc create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/pos/pay.tt create mode 100755 pos/pay.pl --- a/Koha/Charges/Sales.pm +++ a/Koha/Charges/Sales.pm @@ -0,0 +1,285 @@ +package Koha::Charges::Sales; + +# Copyright 2019 PTFS Europe +# +# 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 Koha::Account::Lines; +use Koha::Account::Offsets; +use Koha::DateUtils qw( dt_from_string ); +use Koha::Exceptions; + +=head1 NAME + +Koha::Charges::Sale - Module for collecting sales in Koha + +=head1 SYNOPSIS + + use Koha::Charges::Sale; + + my $sale = + Koha::Charges::Sale->new( { cash_register => $register, staff_id => $staff_id } ); + $sale->add_item($item); + $sale->purchase( { payment_type => 'CASH' } ); + +=head2 Class methods + +=head3 new + + Koha::Charges::Sale->new( + { + cash_register => $cash_register, + staff_id => $staff_id, + [ payment_type => $payment_type ], + [ items => $items ], + [ patron => $patron ], + } + ); + +=cut + +sub new { + my ( $class, $params ) = @_; + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: cash_register") + unless $params->{cash_register}; + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: staff_id") + unless $params->{staff_id}; + + Carp::confess("Key 'cash_register' is not a Koha::Cash::Register object!") + unless $params->{cash_register}->isa('Koha::Cash::Register'); + + return bless( $params, $class ); +} + +=head3 payment_type + + my $payment_type = $sale->payment_type( $payment_type ); + +A getter/setter for this instances associated payment type. + +=cut + +sub payment_type { + my ( $self, $payment_type ) = @_; + + if ($payment_type) { + Koha::Exceptions::Account::UnrecognisedType->throw( + error => 'Type of payment not recognised' ) + unless ( exists( $self->_get_valid_payments->{$payment_type} ) ); + + $self->{payment_type} = $payment_type; + } + + return $self->{payment_type}; +} + +=head3 _get_valid_payments + + my $valid_payments = $sale->_get_valid_payments; + +A getter which returns a hashref whose keys represent valid payment types. + +=cut + +sub _get_valid_payments { + my $self = shift; + + $self->{valid_payments} //= { + map { $_ => 1 } Koha::AuthorisedValues->search( + { + category => 'PAYMENT_TYPE', + branchcode => $self->{cash_register}->branch + } + )->get_column('authorised_value') + }; + + return $self->{valid_payments}; +} + +=head3 add_item + + my $item = { price => 0.25, quantity => 1, code => 'COPY' }; + $sale->add_item( $item ); + +=cut + +sub add_item { + my ( $self, $item ) = @_; + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: code") + unless $item->{code}; + + Koha::Exceptions::Account::UnrecognisedType->throw( + error => 'Type of debit not recognised' ) + unless ( exists( $self->_get_valid_items->{ $item->{code} } ) ); + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: price") + unless $item->{price}; + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: quantity") + unless $item->{quantity}; + + push @{ $self->{items} }, $item; + return $self; +} + +=head3 _get_valid_items + + my $valid_items = $sale->_get_valid_items; + +A getter which returns a hashref whose keys represent valid sale items. + +=cut + +sub _get_valid_items { + my $self = shift; + + $self->{valid_items} //= { + map { $_ => 1 } Koha::AuthorisedValues->search( + { + category => 'MANUAL_INV', + branchcode => $self->{cash_register}->branch + } + )->get_column('authorised_value') + }; + + return $self->{valid_items}; +} + +=head3 purchase + + my $credit_line = $sale->purchase; + +=cut + +sub purchase { + my ( $self, $params ) = @_; + + if ( $params->{payment_type} ) { + Koha::Exceptions::Account::UnrecognisedType->throw( + error => 'Type of payment not recognised' ) + unless ( + exists( $self->_get_valid_payments->{ $params->{payment_type} } ) ); + + $self->{payment_type} = $params->{payment_type}; + } + + Koha::Exceptions::MissingParameter->throw( + "Missing mandatory parameter: payment_type") + unless $self->{payment_type}; + + Koha::Exceptions::NoChanges->throw( + "Cannot purchase before calling add_item") + unless $self->{items}; + + my $schema = Koha::Database->new->schema; + my $dt = dt_from_string(); + my $total_owed = 0; + my $credit; + + $schema->txn_do( + sub { + + # Add accountlines for each item being purchased + my $debits; + for my $item ( @{ $self->{items} } ) { + + my $amount = $item->{quantity} * $item->{price}; + $total_owed = $total_owed + $amount; + + # Insert the account line + my $debit = Koha::Account::Line->new( + { + amount => $amount, + accounttype => $item->{code}, + amountoutstanding => 0, + note => $item->{quantity}, + manager_id => $self->{staff_id}, + interface => 'intranet', + branchcode => $self->{cash_register}->branch, + date => $dt + } + )->store(); + push @{$debits}, $debit; + + # Record the account offset + my $account_offset = Koha::Account::Offset->new( + { + debit_id => $debit->id, + type => 'Purchase', + amount => $amount + } + )->store(); + } + + # Add accountline for payment + $credit = Koha::Account::Line->new( + { + amount => 0 - $total_owed, + accounttype => 'Purchase', + payment_type => $self->{payment_type}, + amountoutstanding => 0, + manager_id => $self->{staff_id}, + interface => 'intranet', + branchcode => $self->{cash_register}->branch, + register_id => $self->{cash_register}->id, + date => $dt, + note => "POS SALE" + } + )->store(); + + # Record the account offset + my $credit_offset = Koha::Account::Offset->new( + { + credit_id => $credit->id, + type => 'Purchase', + amount => $credit->amount + } + )->store(); + + # Link payment to debits + for my $debit ( @{$debits} ) { + Koha::Account::Offset->new( + { + credit_id => $credit->accountlines_id, + debit_id => $debit->id, + amount => $debit->amount * -1, + type => 'Payment', + } + )->store(); + } + } + ); + + return $credit; +} + +=head1 AUTHOR + +Martin Renvoize + +=cut + +1; --- a/installer/data/mysql/account_offset_types.sql +++ a/installer/data/mysql/account_offset_types.sql @@ -1,6 +1,7 @@ INSERT INTO account_offset_types ( type ) VALUES ('Writeoff'), ('Payment'), +('Purchase'), ('Lost Item'), ('Processing Fee'), ('Manual Credit'), --- a/installer/data/mysql/atomicupdate/bug_23354.perl +++ a/installer/data/mysql/atomicupdate/bug_23354.perl @@ -0,0 +1,10 @@ +$DBversion = 'XXX'; # will be replaced by the RM +if( CheckVersion( $DBversion ) ) { + + $dbh->do(q{ + INSERT IGNORE INTO account_offset_types ( type ) VALUES ( 'Purchase' ); + }); + + SetVersion( $DBversion ); + print "Upgrade to $DBversion done (Bug 23354 - Add 'Purchase' account offset type)\n"; +} --- a/koha-tmpl/intranet-tmpl/prog/en/includes/pos-menu.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/pos-menu.inc @@ -0,0 +1,16 @@ + --- a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt @@ -80,6 +80,10 @@