3 # Tests for SIP::ILS::Transaction
4 # Current state is very rudimentary. Please help to extend it!
7 use Test::More tests => 10;
10 use t::lib::TestBuilder;
13 use C4::SIP::ILS::Patron;
14 use C4::SIP::ILS::Transaction::RenewAll;
15 use C4::SIP::ILS::Transaction::Checkout;
16 use C4::SIP::ILS::Transaction::FeePayment;
17 use C4::SIP::ILS::Transaction::Hold;
18 use C4::SIP::ILS::Transaction::Checkout;
19 use C4::SIP::ILS::Transaction::Checkin;
22 use Koha::CirculationRules;
23 use Koha::DateUtils qw( dt_from_string output_pref );
25 my $schema = Koha::Database->new->schema;
26 $schema->storage->txn_begin;
28 my $builder = t::lib::TestBuilder->new();
29 my $borr1 = $builder->build({ source => 'Borrower' });
30 my $card = $borr1->{cardnumber};
31 my $sip_patron = C4::SIP::ILS::Patron->new( $card );
33 # Create transaction RenewAll, assign patron, and run (no items)
34 my $transaction = C4::SIP::ILS::Transaction::RenewAll->new();
35 is( ref $transaction, "C4::SIP::ILS::Transaction::RenewAll", "New transaction created" );
36 is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
37 isnt( $transaction->do_renew_all, undef, "RenewAll on zero items" );
39 subtest fill_holds_at_checkout => sub {
43 my $category = $builder->build({ source => 'Category', value => { category_type => 'A' }});
44 my $branch = $builder->build({ source => 'Branch' });
45 my $borrower = $builder->build({ source => 'Borrower', value =>{
46 branchcode => $branch->{branchcode},
47 categorycode=>$category->{categorycode}
50 t::lib::Mocks::mock_userenv({ branchcode => $branch->{branchcode}, flags => 1 });
52 my $itype = $builder->build({ source => 'Itemtype', value =>{notforloan=>0} });
53 my $item1 = $builder->build_sample_item({
54 barcode => 'barcode4test',
55 homebranch => $branch->{branchcode},
56 holdingbranch => $branch->{branchcode},
57 itype => $itype->{itemtype},
60 my $item2 = $builder->build_sample_item({
61 homebranch => $branch->{branchcode},
62 holdingbranch => $branch->{branchcode},
63 biblionumber => $item1->{biblionumber},
64 itype => $itype->{itemtype},
68 Koha::CirculationRules->set_rules(
70 categorycode => $borrower->{categorycode},
71 branchcode => $branch->{branchcode},
72 itemtype => $itype->{itemtype},
76 holds_per_record => 3,
83 my $reserve1 = AddReserve(
85 branchcode => $branch->{branchcode},
86 borrowernumber => $borrower->{borrowernumber},
87 biblionumber => $item1->{biblionumber}
90 my $reserve2 = AddReserve(
92 branchcode => $branch->{branchcode},
93 borrowernumber => $borrower->{borrowernumber},
94 biblionumber => $item1->{biblionumber}
98 my $bib = Koha::Biblios->find( $item1->{biblionumber} );
99 is( $bib->holds->count(), 2, "Bib has 2 holds");
101 my $sip_patron = C4::SIP::ILS::Patron->new( $borrower->{cardnumber} );
102 my $sip_item = C4::SIP::ILS::Item->new( $item1->{barcode} );
103 my $transaction = C4::SIP::ILS::Transaction::Checkout->new();
104 is( ref $transaction, "C4::SIP::ILS::Transaction::Checkout", "New transaction created" );
105 is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
106 is( $transaction->item( $sip_item ), $sip_item, "Item assigned to transaction" );
107 my $checkout = $transaction->do_checkout();
108 use Data::Dumper; # Temporary debug statement
109 is( $bib->holds->count(), 1, "Bib has 1 holds remaining") or diag Dumper $checkout;
111 t::lib::Mocks::mock_preference('itemBarcodeInputFilter', 'whitespace');
112 $sip_item = C4::SIP::ILS::Item->new( ' barcode 4 test ');
113 $transaction = C4::SIP::ILS::Transaction::Checkout->new();
114 is( $sip_item->{barcode}, $item1->{barcode}, "Item assigned to transaction" );
117 subtest "FeePayment->pay tests" => sub {
121 # Create a borrower and add some outstanding debts to their account
122 my $patron = $builder->build( { source => 'Borrower' } );
124 Koha::Account->new( { patron_id => $patron->{borrowernumber} } );
125 my $debt1 = $account->add_debit(
126 { type => 'ACCOUNT', amount => 100, interface => 'commandline' } );
127 my $debt2 = $account->add_debit(
128 { type => 'ACCOUNT', amount => 200, interface => 'commandline' } );
130 # Instantiate a new FeePayment transaction object
131 my $trans = C4::SIP::ILS::Transaction::FeePayment->new();
134 "C4::SIP::ILS::Transaction::FeePayment",
135 "New fee transaction created"
138 # Test the 'pay' method
139 # FIXME: pay should not require a borrowernumber
140 # (we should reach out to the transaction which should contain a patron object)
141 my $pay_type = '00'; # 00 - Cash, 01 - VISA, 02 - Creditcard
143 $trans->pay( $patron->{borrowernumber}, 100, $pay_type, $debt1->id, 0,
145 ok( $ok, "FeePayment transaction succeeded" );
146 $debt1->discard_changes;
147 is( $debt1->amountoutstanding + 0, 0,
148 "Debt1 was reduced to 0 as expected" );
149 my $offsets = Koha::Account::Offsets->search(
150 { debit_id => $debt1->id, credit_id => { '!=' => undef } } );
151 is( $offsets->count, 1, "FeePayment produced an offset line correctly" );
152 my $credit = $offsets->next->credit;
153 is( $credit->payment_type, 'SIP00', "Payment type was set correctly" );
156 subtest cancel_hold => sub {
159 my $library = $builder->build_object ({ class => 'Koha::Libraries' });
160 my $patron = $builder->build_object(
162 class => 'Koha::Patrons',
164 branchcode => $library->branchcode,
168 t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode, flags => 1 });
170 my $item = $builder->build_sample_item({
171 library => $library->branchcode,
174 Koha::CirculationRules->set_rules(
176 categorycode => $patron->categorycode,
177 branchcode => $library->branchcode,
178 itemtype => $item->effective_itemtype,
181 reservesallowed => 3,
182 holds_per_record => 3,
184 lengthunit => 'days',
189 my $reserve1 = AddReserve(
191 branchcode => $library->branchcode,
192 borrowernumber => $patron->borrowernumber,
193 biblionumber => $item->biblio->biblionumber,
194 itemnumber => $item->itemnumber,
197 is( $item->biblio->holds->count(), 1, "Hold was placed on bib");
198 is( $item->holds->count(),1,"Hold was placed on specific item");
200 my $sip_patron = C4::SIP::ILS::Patron->new( $patron->cardnumber );
201 my $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
202 my $transaction = C4::SIP::ILS::Transaction::Hold->new();
203 is( ref $transaction, "C4::SIP::ILS::Transaction::Hold", "New transaction created" );
204 is( $transaction->patron( $sip_patron ), $sip_patron, "Patron assigned to transaction" );
205 is( $transaction->item( $sip_item ), $sip_item, "Item assigned to transaction" );
206 my $hold = $transaction->drop_hold();
207 is( $item->biblio->holds->count(), 0, "Bib has 0 holds remaining");
208 is( $item->holds->count(), 0, "Item has 0 holds remaining");
211 subtest do_hold => sub {
214 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
215 my $patron_1 = $builder->build_object(
217 class => 'Koha::Patrons',
219 branchcode => $library->branchcode,
223 my $patron_2 = $builder->build_object(
225 class => 'Koha::Patrons',
227 branchcode => $library->branchcode,
228 categorycode => $patron_1->categorycode,
233 t::lib::Mocks::mock_userenv(
234 { branchcode => $library->branchcode, flags => 1 } );
236 my $item = $builder->build_sample_item(
238 library => $library->branchcode,
242 my $reserve1 = AddReserve(
244 branchcode => $library->branchcode,
245 borrowernumber => $patron_1->borrowernumber,
246 biblionumber => $item->biblio->biblionumber,
247 itemnumber => $item->itemnumber,
250 is( $item->biblio->holds->count(), 1, "Hold was placed on bib" );
251 is( $item->holds->count(), 1, "Hold was placed on specific item" );
253 my $sip_patron = C4::SIP::ILS::Patron->new( $patron_2->cardnumber );
254 my $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
255 my $transaction = C4::SIP::ILS::Transaction::Hold->new();
258 "C4::SIP::ILS::Transaction::Hold",
259 "New transaction created"
261 is( $transaction->patron($sip_patron),
262 $sip_patron, "Patron assigned to transaction" );
263 is( $transaction->item($sip_item),
264 $sip_item, "Item assigned to transaction" );
265 my $hold = $transaction->do_hold();
266 is( $item->biblio->holds->count(), 2, "Bib has 2 holds" );
268 my $THE_hold = $patron_2->holds->next;
269 is( $THE_hold->priority, 2, 'Hold placed from SIP should have a correct priority of 2');
270 is( $THE_hold->branchcode, $patron_2->branchcode, 'Hold placed from SIP should have the branchcode set' );
273 subtest do_checkin => sub {
276 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
277 my $patron = $builder->build_object(
279 class => 'Koha::Patrons',
281 branchcode => $library->branchcode,
286 t::lib::Mocks::mock_userenv(
287 { branchcode => $library->branchcode, flags => 1 } );
289 my $item = $builder->build_sample_item(
291 library => $library->branchcode,
297 my $sip_patron = C4::SIP::ILS::Patron->new( $patron->cardnumber );
298 my $sip_item = C4::SIP::ILS::Item->new( $item->barcode );
299 my $co_transaction = C4::SIP::ILS::Transaction::Checkout->new();
300 is( $co_transaction->patron($sip_patron),
301 $sip_patron, "Patron assigned to transaction" );
302 is( $co_transaction->item($sip_item),
303 $sip_item, "Item assigned to transaction" );
304 my $checkout = $co_transaction->do_checkout();
305 is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
308 my $ci_transaction = C4::SIP::ILS::Transaction::Checkin->new();
309 is( $ci_transaction->patron($sip_patron),
310 $sip_patron, "Patron assigned to transaction" );
311 is( $ci_transaction->item($sip_item),
312 $sip_item, "Item assigned to transaction" );
314 my $checkin = $ci_transaction->do_checkin($library->branchcode, C4::SIP::Sip::timestamp);
315 is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
317 # Test checkin without return date
318 $co_transaction->do_checkout;
319 is( $patron->checkouts->count, 1, 'Checkout should have been done successfully');
320 $ci_transaction->do_checkin($library->branchcode, undef);
321 is( $patron->checkouts->count, 0, 'Checkin should have been done successfully');
324 subtest checkin_lost => sub {
327 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
329 t::lib::Mocks::mock_userenv(
330 { branchcode => $library->branchcode, flags => 1 } );
332 my $item = $builder->build_sample_item(
334 library => $library->branchcode,
338 $item->itemlost(1)->itemlost_on(dt_from_string)->store();
342 implementation => "ILS",
351 my $ils = C4::SIP::ILS->new( $instituation );
353 t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '1');
354 my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp );
355 is( $circ->{screen_msg}, 'Item lost, return not allowed', "Got correct screen message" );
357 t::lib::Mocks::mock_preference('BlockReturnOfLostItems', '0');
358 $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp );
359 is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
362 subtest checkin_withdrawn => sub {
365 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
367 t::lib::Mocks::mock_userenv(
368 { branchcode => $library->branchcode, flags => 1 } );
370 my $item = $builder->build_sample_item(
372 library => $library->branchcode,
376 $item->withdrawn(1)->withdrawn_on(dt_from_string)->store();
380 implementation => "ILS",
389 my $ils = C4::SIP::ILS->new( $instituation );
391 t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '1');
392 my $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp );
393 is( $circ->{screen_msg}, 'Item withdrawn, return not allowed', "Got correct screen message" );
395 t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', '0');
396 $circ = $ils->checkin( $item->barcode, C4::SIP::Sip::timestamp );
397 is( $circ->{screen_msg}, 'Item not checked out', "Got 'Item not checked out' screen message" );
399 $schema->storage->txn_rollback;