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

(-)a/t/Edifact_RFF_ON.t (+107 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Test for RFF+ON (Purchase Order Number) segment handling in EDIFACT messages
4
# Bug 20253: Optionally use buyer's purchase order number from EDIFACT quote in basket name
5
# Note: RFF+ON is a message-level segment only, not line-level
6
7
use strict;
8
use warnings;
9
use Test::More tests => 4;
10
11
BEGIN { 
12
    use_ok('Koha::Edifact::Message');
13
}
14
15
# Mock segment class for testing
16
{
17
    package MockSegment;
18
    sub new {
19
        my ($class, $tag, $elements) = @_;
20
        return bless { tag => $tag, elements => $elements }, $class;
21
    }
22
    
23
    sub tag {
24
        my $self = shift;
25
        return $self->{tag};
26
    }
27
    
28
    sub elem {
29
        my ($self, $comp_pos, $elem_pos) = @_;
30
        return $self->{elements}->[$comp_pos]->[$elem_pos // 0];
31
    }
32
}
33
34
# Test RFF+ON segment handling at message level
35
subtest 'RFF+ON segment handling in Message' => sub {
36
    plan tests => 2;
37
    
38
    # Create mock message segments (message-level segments before first LIN)
39
    my @datasegs = (
40
        MockSegment->new('NAD', [['BY'], ['5030670137480', '', '', 'Buyer Name']]),
41
        MockSegment->new('RFF', [['ON', 'MSG_PO_12345']]),     # Message-level purchase order number
42
        MockSegment->new('NAD', [['SU'], ['5013546027856', '', '', 'Supplier Name']]),
43
        MockSegment->new('LIN', [['1'], ['', ''], ['9780123456789', 'EN']]),  # First line item
44
        MockSegment->new('QTY', [['47', '1']]),
45
    );
46
    
47
    # Create mock header and BGM for Message constructor
48
    my $header = MockSegment->new('UNH', [['MQ09791'], ['QUOTES', 'D', '03B', 'UN', 'EAN008']]);
49
    my $bgm = MockSegment->new('BGM', [['310', 'Q741588', '9']]);
50
    
51
    my $message = Koha::Edifact::Message->new([$header, $bgm, @datasegs]);
52
    
53
    # Test that message-level purchase order number is extracted
54
    is($message->purchase_order_number, 'MSG_PO_12345', 'Message-level purchase order number extracted from RFF+ON segment');
55
    
56
    # Test message without RFF+ON segment
57
    @datasegs = (
58
        MockSegment->new('NAD', [['BY'], ['5030670137480', '', '', 'Buyer Name']]),
59
        MockSegment->new('NAD', [['SU'], ['5013546027856', '', '', 'Supplier Name']]),
60
        MockSegment->new('LIN', [['1'], ['', ''], ['9780123456789', 'EN']]),
61
        MockSegment->new('QTY', [['47', '1']]),
62
    );
63
    
64
    $message = Koha::Edifact::Message->new([$header, $bgm, @datasegs]);
65
    is($message->purchase_order_number, undef, 'Returns undef when no RFF+ON segment present');
66
};
67
68
# Test that RFF+ON processing stops at first LIN segment (message-level only)
69
subtest 'Message-level RFF+ON processing stops at LIN' => sub {
70
    plan tests => 1;
71
    
72
    my @datasegs = (
73
        MockSegment->new('NAD', [['BY'], ['5030670137480', '', '', 'Buyer Name']]),
74
        MockSegment->new('LIN', [['1'], ['', ''], ['9780123456789', 'EN']]),  # First LIN
75
        MockSegment->new('RFF', [['ON', 'AFTER_LIN_PO']]),     # This should be ignored (line-level)
76
        MockSegment->new('QTY', [['47', '1']]),
77
    );
78
    
79
    my $header = MockSegment->new('UNH', [['MQ09791'], ['QUOTES', 'D', '03B', 'UN', 'EAN008']]);
80
    my $bgm = MockSegment->new('BGM', [['310', 'Q741588', '9']]);
81
    
82
    my $message = Koha::Edifact::Message->new([$header, $bgm, @datasegs]);
83
    
84
    is($message->purchase_order_number, undef, 'RFF+ON after LIN segment is ignored (message-level only)');
85
};
86
87
# Test multiple RFF segments at message level
88
subtest 'Multiple RFF segments at message level' => sub {
89
    plan tests => 1;
90
    
91
    my @datasegs = (
92
        MockSegment->new('NAD', [['BY'], ['5030670137480', '', '', 'Buyer Name']]),
93
        MockSegment->new('RFF', [['QLI', 'QUOTE_REF_123']]),   # Different RFF qualifier
94
        MockSegment->new('RFF', [['ON', 'CORRECT_PO_NUM']]),   # Purchase order number
95
        MockSegment->new('RFF', [['CT', 'CONTRACT_456']]),     # Another different RFF qualifier
96
        MockSegment->new('NAD', [['SU'], ['5013546027856', '', '', 'Supplier Name']]),
97
        MockSegment->new('LIN', [['1'], ['', ''], ['9780123456789', 'EN']]),
98
        MockSegment->new('QTY', [['47', '1']]),
99
    );
100
    
101
    my $header = MockSegment->new('UNH', [['MQ09791'], ['QUOTES', 'D', '03B', 'UN', 'EAN008']]);
102
    my $bgm = MockSegment->new('BGM', [['310', 'Q741588', '9']]);
103
    
104
    my $message = Koha::Edifact::Message->new([$header, $bgm, @datasegs]);
105
    
106
    is($message->purchase_order_number, 'CORRECT_PO_NUM', 'Correct RFF+ON extracted when multiple RFF segments present');
107
};
(-)a/t/db_dependent/Koha/EDI.t (-2 / +118 lines)
Lines 38-44 my $builder = t::lib::TestBuilder->new; Link Here
38
my $logger  = t::lib::Mocks::Logger->new();
38
my $logger  = t::lib::Mocks::Logger->new();
39
39
40
subtest 'process_quote' => sub {
40
subtest 'process_quote' => sub {
41
    plan tests => 5;
41
    plan tests => 6;
42
42
43
    $schema->storage->txn_begin;
43
    $schema->storage->txn_begin;
44
44
Lines 634-639 subtest 'process_quote' => sub { Link Here
634
        $schema->storage->txn_rollback;
634
        $schema->storage->txn_rollback;
635
    };
635
    };
636
636
637
    # Test 6: Basket naming configuration
638
    subtest 'basket_naming_configuration' => sub {
639
        plan tests => 6;
640
641
        $schema->storage->txn_begin;
642
643
        # Create vendor EDI account with basket_name_source set to filename (default)
644
        my $account_filename = $builder->build(
645
            {
646
                source => 'VendorEdiAccount',
647
                value  => {
648
                    description        => 'test vendor filename',
649
                    transport          => 'FILE',
650
                    plugin             => '',
651
                    san                => $test_san,
652
                    quotes_enabled     => 1,
653
                    auto_orders        => 0,
654
                    basket_name_source => 'filename',
655
                }
656
            }
657
        );
658
659
        # Create vendor EDI account with basket_name_source set to purchase_order_number
660
        my $account_po = $builder->build(
661
            {
662
                source => 'VendorEdiAccount',
663
                value  => {
664
                    description        => 'test vendor purchase order',
665
                    transport          => 'FILE',
666
                    plugin             => '',
667
                    san                => $test_san,
668
                    quotes_enabled     => 1,
669
                    auto_orders        => 0,
670
                    basket_name_source => 'purchase_order_number',
671
                }
672
            }
673
        );
674
675
        # Test database field storage
676
        my $account = $schema->resultset('VendorEdiAccount')->find($account_filename->{id});
677
        is($account->basket_name_source, 'filename', 'basket_name_source field stores filename value');
678
        
679
        $account = $schema->resultset('VendorEdiAccount')->find($account_po->{id});
680
        is($account->basket_name_source, 'purchase_order_number', 'basket_name_source field stores purchase_order_number value');
681
682
        # Test enum constraint - valid values
683
        eval { $account->update({ basket_name_source => 'filename' }); };
684
        is($@, '', 'filename is accepted as valid enum value');
685
        
686
        eval { $account->update({ basket_name_source => 'purchase_order_number' }); };
687
        is($@, '', 'purchase_order_number is accepted as valid enum value');
688
689
        # Test default behavior when field is null
690
        my $account_default = $builder->build(
691
            {
692
                source => 'VendorEdiAccount',
693
                value  => {
694
                    description    => 'test vendor default',
695
                    transport      => 'FILE',
696
                    plugin         => '',
697
                    san            => $test_san,
698
                    quotes_enabled => 1,
699
                    auto_orders    => 0,
700
                    # basket_name_source not specified, should default
701
                }
702
            }
703
        );
704
        
705
        $account = $schema->resultset('VendorEdiAccount')->find($account_default->{id});
706
        is($account->basket_name_source // 'filename', 'filename', 'basket_name_source defaults to filename when not specified');
707
708
        # Mock NewBasket to capture basket name
709
        my $captured_basket_name;
710
        my $mock_acquisition = Test::MockModule->new('C4::Acquisition', no_auto => 1);
711
        $mock_acquisition->mock('NewBasket', sub {
712
            my ($vendor_id, $authorisedby, $basketname, $basketnote, $basketbooksellernote) = @_;
713
            $captured_basket_name = $basketname;
714
            return 1; # Return a basket ID
715
        });
716
717
        # Mock message with purchase order number
718
        my $mock_message = Test::MockModule->new('Koha::Edifact::Message');
719
        $mock_message->mock('purchase_order_number', sub { return 'TEST_PO_123456'; });
720
        $mock_message->mock('lineitems', sub { return []; });
721
        $mock_message->mock('buyer_ean', sub { return $test_san; });
722
723
        # Create a quote message for testing
724
        my $quote_message = $builder->build(
725
            {
726
                source => 'EdifactMessage',
727
                value  => {
728
                    message_type => 'QUOTE',
729
                    vendor_id    => $account_po->{vendor_id},
730
                    filename     => 'test_basket_naming.ceq',
731
                    status       => 'recmsg',
732
                }
733
            }
734
        );
735
736
        # Test that the logic would use purchase order number when configured
737
        # (This tests the logic in process_quote without running the full process)
738
        my $v = $schema->resultset('VendorEdiAccount')->search({ vendor_id => $account_po->{vendor_id} })->single;
739
        my $quote_obj = $schema->resultset('EdifactMessage')->find($quote_message->{id});
740
        my $basket_name = $quote_obj->filename;
741
        
742
        if ($v && $v->basket_name_source && $v->basket_name_source eq 'purchase_order_number') {
743
            my $purchase_order_number = 'TEST_PO_123456'; # Simulated from mock
744
            if ($purchase_order_number) {
745
                $basket_name = $purchase_order_number;
746
            }
747
        }
748
        
749
        is($basket_name, 'TEST_PO_123456', 'Basket naming logic correctly uses purchase order number when configured');
750
751
        $schema->storage->txn_rollback;
752
    };
753
637
    # Clean up
754
    # Clean up
638
    $logger->clear();
755
    $logger->clear();
639
    $schema->storage->txn_rollback;
756
    $schema->storage->txn_rollback;
640
- 

Return to bug 20253