Bug 12556: Add new "in processing" state to holds
[koha.git] / Koha / Charges / Sales.pm
1 package Koha::Charges::Sales;
2
3 # Copyright 2019 PTFS Europe
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Koha::Account::Lines;
23 use Koha::Account::DebitTypes;
24 use Koha::Account::Offsets;
25 use Koha::DateUtils qw( dt_from_string );
26 use Koha::Exceptions;
27
28 =head1 NAME
29
30 Koha::Charges::Sale - Module for collecting sales in Koha
31
32 =head1 SYNOPSIS
33
34   use Koha::Charges::Sale;
35
36   my $sale =
37     Koha::Charges::Sale->new( { cash_register => $register, staff_id => $staff_id } );
38   $sale->add_item($item);
39   $sale->purchase( { payment_type => 'CASH' } );
40
41 =head2 Class methods
42
43 =head3 new
44
45   Koha::Charges::Sale->new(
46     {
47         cash_register  => $cash_register,
48         staff_id        => $staff_id,
49         [ payment_type => $payment_type ],
50         [ items        => $items ],
51         [ patron       => $patron ],
52     }
53   );
54
55 =cut
56
57 sub new {
58     my ( $class, $params ) = @_;
59
60     Koha::Exceptions::MissingParameter->throw(
61         "Missing mandatory parameter: cash_register")
62       unless $params->{cash_register};
63
64     Koha::Exceptions::MissingParameter->throw(
65         "Missing mandatory parameter: staff_id")
66       unless $params->{staff_id};
67
68     Carp::confess("Key 'cash_register' is not a Koha::Cash::Register object!")
69       unless $params->{cash_register}->isa('Koha::Cash::Register');
70
71     return bless( $params, $class );
72 }
73
74 =head3 payment_type
75
76   my $payment_type = $sale->payment_type( $payment_type );
77
78 A getter/setter for this instances associated payment type.
79
80 =cut
81
82 sub payment_type {
83     my ( $self, $payment_type ) = @_;
84
85     if ($payment_type) {
86         Koha::Exceptions::Account::UnrecognisedType->throw(
87             error => 'Type of payment not recognised' )
88           unless ( exists( $self->_get_valid_payments->{$payment_type} ) );
89
90         $self->{payment_type} = $payment_type;
91     }
92
93     return $self->{payment_type};
94 }
95
96 =head3 _get_valid_payments
97
98   my $valid_payments = $sale->_get_valid_payments;
99
100 A getter which returns a hashref whose keys represent valid payment types.
101
102 =cut
103
104 sub _get_valid_payments {
105     my $self = shift;
106
107     $self->{valid_payments} //= {
108         map { $_ => 1 } Koha::AuthorisedValues->search(
109             {
110                 category   => 'PAYMENT_TYPE',
111                 branchcode => $self->{cash_register}->branch
112             }
113         )->get_column('authorised_value')
114     };
115
116     return $self->{valid_payments};
117 }
118
119 =head3 add_item
120
121   my $item = { price => 0.25, quantity => 1, code => 'COPY' };
122   $sale->add_item( $item );
123
124 =cut
125
126 sub add_item {
127     my ( $self, $item ) = @_;
128
129     Koha::Exceptions::MissingParameter->throw(
130         "Missing mandatory parameter: code")
131       unless $item->{code};
132
133     Koha::Exceptions::Account::UnrecognisedType->throw(
134         error => 'Type of debit not recognised' )
135       unless ( exists( $self->_get_valid_items->{ $item->{code} } ) );
136
137     Koha::Exceptions::MissingParameter->throw(
138         "Missing mandatory parameter: price")
139       unless $item->{price};
140
141     Koha::Exceptions::MissingParameter->throw(
142         "Missing mandatory parameter: quantity")
143       unless $item->{quantity};
144
145     push @{ $self->{items} }, $item;
146     return $self;
147 }
148
149 =head3 _get_valid_items
150
151   my $valid_items = $sale->_get_valid_items;
152
153 A getter which returns a hashref whose keys represent valid sale items.
154
155 =cut
156
157 sub _get_valid_items {
158     my $self = shift;
159
160     $self->{valid_items} //= {
161         map { $_ => 1 }
162           Koha::Account::DebitTypes->search_with_library_limits( {}, {},
163             $self->{cash_register}->branch )->get_column('code')
164     };
165
166     return $self->{valid_items};
167 }
168
169 =head3 purchase
170
171   my $credit_line = $sale->purchase;
172
173 =cut
174
175 sub purchase {
176     my ( $self, $params ) = @_;
177
178     if ( $params->{payment_type} ) {
179         Koha::Exceptions::Account::UnrecognisedType->throw(
180             error => 'Type of payment not recognised' )
181           unless (
182             exists( $self->_get_valid_payments->{ $params->{payment_type} } ) );
183
184         $self->{payment_type} = $params->{payment_type};
185     }
186
187     Koha::Exceptions::MissingParameter->throw(
188         "Missing mandatory parameter: payment_type")
189       unless $self->{payment_type};
190
191     Koha::Exceptions::NoChanges->throw(
192         "Cannot purchase before calling add_item")
193       unless $self->{items};
194
195     my $schema     = Koha::Database->new->schema;
196     my $dt         = dt_from_string();
197     my $total_owed = 0;
198     my $credit;
199
200     $schema->txn_do(
201         sub {
202
203             # Add accountlines for each item being purchased
204             my $debits;
205             for my $item ( @{ $self->{items} } ) {
206
207                 my $amount = $item->{quantity} * $item->{price};
208                 $total_owed = $total_owed + $amount;
209
210                 # Insert the account line
211                 my $debit = Koha::Account::Line->new(
212                     {
213                         amount            => $amount,
214                         debit_type_code   => $item->{code},
215                         amountoutstanding => 0,
216                         note              => $item->{quantity},
217                         manager_id        => $self->{staff_id},
218                         interface         => 'intranet',
219                         branchcode        => $self->{cash_register}->branch,
220                         date              => $dt
221                     }
222                 )->store();
223                 push @{$debits}, $debit;
224
225                 # Record the account offset
226                 my $account_offset = Koha::Account::Offset->new(
227                     {
228                         debit_id => $debit->id,
229                         type     => 'Purchase',
230                         amount   => $amount
231                     }
232                 )->store();
233             }
234
235             # Add accountline for payment
236             $credit = Koha::Account::Line->new(
237                 {
238                     amount            => 0 - $total_owed,
239                     credit_type_code  => 'PURCHASE',
240                     payment_type      => $self->{payment_type},
241                     amountoutstanding => 0,
242                     manager_id        => $self->{staff_id},
243                     interface         => 'intranet',
244                     branchcode        => $self->{cash_register}->branch,
245                     register_id       => $self->{cash_register}->id,
246                     date              => $dt,
247                     note              => "POS SALE"
248                 }
249             )->store();
250
251             # Record the account offset
252             my $credit_offset = Koha::Account::Offset->new(
253                 {
254                     credit_id => $credit->id,
255                     type      => 'Purchase',
256                     amount    => $credit->amount
257                 }
258             )->store();
259
260             # Link payment to debits
261             for my $debit ( @{$debits} ) {
262                 Koha::Account::Offset->new(
263                     {
264                         credit_id => $credit->accountlines_id,
265                         debit_id  => $debit->id,
266                         amount    => $debit->amount * -1,
267                         type      => 'Payment',
268                     }
269                 )->store();
270             }
271         }
272     );
273
274     return $credit;
275 }
276
277 =head1 AUTHOR
278
279 Martin Renvoize <martin.renvoize@ptfs-europe.com>
280
281 =cut
282
283 1;