View | Details | Raw Unified | Return to bug 40445
Collapse All | Expand All

(-)a/t/db_dependent/Koha/Cash/Register.t (-2 / +434 lines)
Lines 20-30 Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::NoWarnings;
22
use Test::NoWarnings;
23
use Test::More tests => 5;
23
use Test::More tests => 6;
24
24
25
use Test::Exception;
25
use Test::Exception;
26
26
27
use Koha::Database;
27
use Koha::Database;
28
use Koha::Account;
29
use Koha::Account::CreditTypes;
30
use Koha::Account::DebitTypes;
28
31
29
use t::lib::TestBuilder;
32
use t::lib::TestBuilder;
30
33
Lines 312-314 subtest 'cashup' => sub { Link Here
312
315
313
    $schema->storage->txn_rollback;
316
    $schema->storage->txn_rollback;
314
};
317
};
315
- 
318
319
subtest 'cashup_reconciliation' => sub {
320
    plan tests => 5;
321
322
    $schema->storage->txn_begin;
323
324
    # Ensure required account types for reconciliation exist (they should already exist from mandatory data)
325
    use Koha::Account::CreditTypes;
326
    use Koha::Account::DebitTypes;
327
328
    my $surplus_credit_type = Koha::Account::CreditTypes->find( { code => 'CASHUP_SURPLUS' } );
329
    if ( !$surplus_credit_type ) {
330
        $surplus_credit_type = $builder->build_object(
331
            {
332
                class => 'Koha::Account::CreditTypes',
333
                value => {
334
                    code                  => 'CASHUP_SURPLUS',
335
                    description           => 'Cash register surplus found during cashup',
336
                    can_be_added_manually => 0,
337
                    credit_number_enabled => 0,
338
                    is_system             => 1,
339
                    archived              => 0,
340
                }
341
            }
342
        );
343
    }
344
345
    my $deficit_debit_type = Koha::Account::DebitTypes->find( { code => 'CASHUP_DEFICIT' } );
346
    if ( !$deficit_debit_type ) {
347
        $deficit_debit_type = $builder->build_object(
348
            {
349
                class => 'Koha::Account::DebitTypes',
350
                value => {
351
                    code                => 'CASHUP_DEFICIT',
352
                    description         => 'Cash register deficit found during cashup',
353
                    can_be_invoiced     => 0,
354
                    can_be_sold         => 0,
355
                    default_amount      => undef,
356
                    is_system           => 1,
357
                    archived            => 0,
358
                    restricts_checkouts => 0,
359
                }
360
            }
361
        );
362
    }
363
364
    my $register = $builder->build_object( { class => 'Koha::Cash::Registers' } );
365
    my $patron   = $builder->build_object( { class => 'Koha::Patrons' } );
366
367
    # Create some outstanding accountlines to establish expected amount
368
    my $accountline1 = $builder->build_object(
369
        {
370
            class => 'Koha::Account::Lines',
371
            value => {
372
                register_id      => $register->id,
373
                borrowernumber   => $patron->id,
374
                amount           => -10.00,          # Credit (payment)
375
                credit_type_code => 'PAYMENT',
376
                debit_type_code  => undef,
377
            }
378
        }
379
    );
380
    my $accountline2 = $builder->build_object(
381
        {
382
            class => 'Koha::Account::Lines',
383
            value => {
384
                register_id      => $register->id,
385
                borrowernumber   => $patron->id,
386
                amount           => -5.00,           # Credit (payment)
387
                credit_type_code => 'PAYMENT',
388
                debit_type_code  => undef,
389
            }
390
        }
391
    );
392
393
    my $expected_amount = $register->outstanding_accountlines->total;    # Should be -15.00
394
395
    subtest 'balanced_cashup' => sub {
396
        plan tests => 3;
397
398
        # Test exact match - no surplus/deficit accountlines should be created
399
        my $amount = abs($expected_amount);                              # 15.00 actual matches 15.00 expected
400
401
        my $cashup = $register->add_cashup(
402
            {
403
                manager_id => $patron->id,
404
                amount     => $amount
405
            }
406
        );
407
408
        ok( $cashup, 'Cashup created successfully' );
409
        is( sprintf( '%.0f', $cashup->amount ), sprintf( '%.0f', $amount ), 'Cashup amount matches actual amount' );
410
411
        # Check no surplus/deficit accountlines were created
412
        my $reconciliation_lines = Koha::Account::Lines->search(
413
            {
414
                register_id => $register->id,
415
                '-or'       => [
416
                    { credit_type_code => 'CASHUP_SURPLUS' },
417
                    { debit_type_code  => 'CASHUP_DEFICIT' }
418
                ]
419
            }
420
        );
421
422
        is( $reconciliation_lines->count, 0, 'No reconciliation accountlines created for balanced cashup' );
423
    };
424
425
    subtest 'surplus_cashup' => sub {
426
        plan tests => 7;
427
428
        $schema->storage->txn_begin;
429
430
        my $register2    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
431
        my $accountline3 = $builder->build_object(
432
            {
433
                class => 'Koha::Account::Lines',
434
                value => {
435
                    register_id      => $register2->id,
436
                    borrowernumber   => $patron->id,
437
                    amount           => -20.00,           # Credit (payment)
438
                    credit_type_code => 'PAYMENT',
439
                    debit_type_code  => undef,
440
                }
441
            }
442
        );
443
444
        my $expected = abs( $register2->outstanding_accountlines->total );    # 20.00
445
        my $actual   = 25.00;                                                 # 5.00 surplus
446
        my $surplus  = $actual - $expected;
447
448
        my $cashup = $register2->add_cashup(
449
            {
450
                manager_id => $patron->id,
451
                amount     => $actual
452
            }
453
        );
454
455
        ok( $cashup, 'Surplus cashup created successfully' );
456
        is( sprintf( '%.0f', $cashup->amount ), sprintf( '%.0f', $actual ), 'Cashup amount matches actual amount' );
457
458
        # Check surplus accountline was created
459
        my $surplus_lines = Koha::Account::Lines->search(
460
            {
461
                register_id      => $register2->id,
462
                credit_type_code => 'CASHUP_SURPLUS'
463
            }
464
        );
465
466
        is( $surplus_lines->count, 1, 'One surplus accountline created' );
467
468
        my $surplus_line = $surplus_lines->next;
469
        is(
470
            sprintf( '%.0f', $surplus_line->amount ), sprintf( '%.0f', -$surplus ),
471
            'Surplus amount is correct (negative for credit)'
472
        );
473
474
        # Note should be undef for surplus without user note
475
        is( $surplus_line->note, undef, 'No note for surplus without user reconciliation note' );
476
477
        # Test surplus with user note
478
        my $register_with_note    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
479
        my $accountline_with_note = $builder->build_object(
480
            {
481
                class => 'Koha::Account::Lines',
482
                value => {
483
                    register_id      => $register_with_note->id,
484
                    borrowernumber   => $patron->id,
485
                    amount           => -10.00,
486
                    credit_type_code => 'PAYMENT',
487
                    debit_type_code  => undef,
488
                }
489
            }
490
        );
491
492
        my $cashup_with_note = $register_with_note->add_cashup(
493
            {
494
                manager_id          => $patron->id,
495
                amount              => 15.00,                                           # 5.00 surplus
496
                reconciliation_note => 'Found extra \x{00A3}5 under the till drawer'    # £5 in UTF-8
497
            }
498
        );
499
500
        my $surplus_with_note = Koha::Account::Lines->search(
501
            {
502
                register_id      => $register_with_note->id,
503
                credit_type_code => 'CASHUP_SURPLUS'
504
            }
505
        )->next;
506
507
        like(
508
            $surplus_with_note->note, qr/Found extra .+5 under the till drawer/,
509
            'User note included in surplus accountline'
510
        );
511
        is(
512
            $surplus_with_note->note, 'Found extra \x{00A3}5 under the till drawer',
513
            'Only user note stored (no base reconciliation info)'
514
        );
515
516
        $schema->storage->txn_rollback;
517
    };
518
519
    subtest 'deficit_cashup' => sub {
520
        plan tests => 7;
521
522
        $schema->storage->txn_begin;
523
524
        my $register3    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
525
        my $accountline4 = $builder->build_object(
526
            {
527
                class => 'Koha::Account::Lines',
528
                value => {
529
                    register_id      => $register3->id,
530
                    borrowernumber   => $patron->id,
531
                    amount           => -30.00,           # Credit (payment)
532
                    credit_type_code => 'PAYMENT',
533
                    debit_type_code  => undef,
534
                }
535
            }
536
        );
537
538
        my $expected = abs( $register3->outstanding_accountlines->total );    # 30.00
539
        my $actual   = 25.00;                                                 # 5.00 deficit
540
        my $deficit  = $expected - $actual;
541
542
        my $cashup = $register3->add_cashup(
543
            {
544
                manager_id => $patron->id,
545
                amount     => $actual
546
            }
547
        );
548
549
        ok( $cashup, 'Deficit cashup created successfully' );
550
        is( sprintf( '%.0f', $cashup->amount ), sprintf( '%.0f', $actual ), 'Cashup amount matches actual amount' );
551
552
        # Check deficit accountline was created
553
        my $deficit_lines = Koha::Account::Lines->search(
554
            {
555
                register_id     => $register3->id,
556
                debit_type_code => 'CASHUP_DEFICIT'
557
            }
558
        );
559
560
        is( $deficit_lines->count, 1, 'One deficit accountline created' );
561
562
        my $deficit_line = $deficit_lines->next;
563
        is(
564
            sprintf( '%.0f', $deficit_line->amount ), sprintf( '%.0f', $deficit ),
565
            'Deficit amount is correct (positive for debit)'
566
        );
567
568
        # Note should be undef for deficit without user note
569
        is( $deficit_line->note, undef, 'No note for deficit without user reconciliation note' );
570
571
        # Test deficit with user note
572
        my $register_deficit_note    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
573
        my $accountline_deficit_note = $builder->build_object(
574
            {
575
                class => 'Koha::Account::Lines',
576
                value => {
577
                    register_id      => $register_deficit_note->id,
578
                    borrowernumber   => $patron->id,
579
                    amount           => -20.00,
580
                    credit_type_code => 'PAYMENT',
581
                    debit_type_code  => undef,
582
                }
583
            }
584
        );
585
586
        my $cashup_deficit_note = $register_deficit_note->add_cashup(
587
            {
588
                manager_id          => $patron->id,
589
                amount              => 15.00,                                                     # 5.00 deficit
590
                reconciliation_note => 'Till was short, possibly due to incorrect change given'
591
            }
592
        );
593
594
        my $deficit_with_note = Koha::Account::Lines->search(
595
            {
596
                register_id     => $register_deficit_note->id,
597
                debit_type_code => 'CASHUP_DEFICIT'
598
            }
599
        )->next;
600
601
        like(
602
            $deficit_with_note->note, qr/Till was short, possibly due to incorrect change given/,
603
            'User note included in deficit accountline'
604
        );
605
        is(
606
            $deficit_with_note->note, 'Till was short, possibly due to incorrect change given',
607
            'Only user note stored (no base reconciliation info)'
608
        );
609
610
        $schema->storage->txn_rollback;
611
    };
612
613
    subtest 'transaction_integrity' => sub {
614
        plan tests => 4;
615
616
        $schema->storage->txn_begin;
617
618
        my $register4    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
619
        my $accountline5 = $builder->build_object(
620
            {
621
                class => 'Koha::Account::Lines',
622
                value => {
623
                    register_id      => $register4->id,
624
                    borrowernumber   => $patron->id,
625
                    amount           => -10.00,
626
                    credit_type_code => 'PAYMENT',
627
                    debit_type_code  => undef,
628
                }
629
            }
630
        );
631
632
        my $initial_accountline_count = Koha::Account::Lines->search( { register_id => $register4->id } )->count;
633
634
        my $initial_action_count = $register4->cashups->count;
635
636
        # Test successful transaction
637
        my $cashup = $register4->add_cashup(
638
            {
639
                manager_id => $patron->id,
640
                amount     => 15.00          # Creates surplus
641
            }
642
        );
643
644
        # Check both cashup action and surplus accountline were created
645
        is( $register4->cashups->count, $initial_action_count + 1, 'Cashup action created' );
646
647
        my $final_accountline_count = Koha::Account::Lines->search( { register_id => $register4->id } )->count;
648
649
        is( $final_accountline_count, $initial_accountline_count + 1, 'Surplus accountline created' );
650
651
        # Verify the new accountline is the surplus
652
        my $surplus_line = Koha::Account::Lines->search(
653
            {
654
                register_id      => $register4->id,
655
                credit_type_code => 'CASHUP_SURPLUS'
656
            }
657
        )->next;
658
659
        ok( $surplus_line, 'Surplus accountline exists' );
660
        is( $surplus_line->register_id, $register4->id, 'Surplus linked to correct register' );
661
662
        $schema->storage->txn_rollback;
663
    };
664
665
    subtest 'note_handling' => sub {
666
        plan tests => 2;
667
668
        $schema->storage->txn_begin;
669
670
        my $register_note_test    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
671
        my $accountline_note_test = $builder->build_object(
672
            {
673
                class => 'Koha::Account::Lines',
674
                value => {
675
                    register_id      => $register_note_test->id,
676
                    borrowernumber   => $patron->id,
677
                    amount           => -10.00,
678
                    credit_type_code => 'PAYMENT',
679
                    debit_type_code  => undef,
680
                }
681
            }
682
        );
683
684
        # Test balanced cashup with note (should not create surplus/deficit)
685
        my $balanced_cashup = $register_note_test->add_cashup(
686
            {
687
                manager_id          => $patron->id,
688
                amount              => 10.00,                                              # Balanced
689
                reconciliation_note => 'This note should be ignored for balanced cashup'
690
            }
691
        );
692
693
        my $balanced_reconciliation_lines = Koha::Account::Lines->search(
694
            {
695
                register_id => $register_note_test->id,
696
                '-or'       => [
697
                    { credit_type_code => 'CASHUP_SURPLUS' },
698
                    { debit_type_code  => 'CASHUP_DEFICIT' }
699
                ]
700
            }
701
        );
702
703
        is(
704
            $balanced_reconciliation_lines->count, 0,
705
            'No reconciliation accountlines created for balanced cashup with note'
706
        );
707
708
        # Test empty/whitespace note handling
709
        my $register_empty_note    = $builder->build_object( { class => 'Koha::Cash::Registers' } );
710
        my $accountline_empty_note = $builder->build_object(
711
            {
712
                class => 'Koha::Account::Lines',
713
                value => {
714
                    register_id      => $register_empty_note->id,
715
                    borrowernumber   => $patron->id,
716
                    amount           => -10.00,
717
                    credit_type_code => 'PAYMENT',
718
                    debit_type_code  => undef,
719
                }
720
            }
721
        );
722
723
        my $empty_note_cashup = $register_empty_note->add_cashup(
724
            {
725
                manager_id          => $patron->id,
726
                amount              => 12.00,         # 2.00 surplus
727
                reconciliation_note => '   '          # Whitespace only
728
            }
729
        );
730
731
        my $empty_note_surplus = Koha::Account::Lines->search(
732
            {
733
                register_id      => $register_empty_note->id,
734
                credit_type_code => 'CASHUP_SURPLUS'
735
            }
736
        )->next;
737
738
        is(
739
            $empty_note_surplus->note, undef,
740
            'No note stored when user note is empty/whitespace'
741
        );
742
743
        $schema->storage->txn_rollback;
744
    };
745
746
    $schema->storage->txn_rollback;
747
};

Return to bug 40445