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

(-)a/t/Edifact.t (-1 / +46 lines)
Lines 4-10 use warnings; Link Here
4
use FindBin qw( $Bin );
4
use FindBin qw( $Bin );
5
5
6
use Test::NoWarnings;
6
use Test::NoWarnings;
7
use Test::More tests => 42;
7
use Test::More tests => 49;
8
use Koha::EDI;
8
use Koha::EDI;
9
9
10
BEGIN { use_ok('Koha::Edifact') }
10
BEGIN { use_ok('Koha::Edifact') }
Lines 139-141 is( $dp, 9.0, 'Discount calculated with discount = 0' ); Link Here
139
139
140
$dp = Koha::EDI::_discounted_price( 0.0, 9, 8.0 );
140
$dp = Koha::EDI::_discounted_price( 0.0, 9, 8.0 );
141
is( $dp, 8.0, 'Discount overridden by incoming calculated value' );
141
is( $dp, 8.0, 'Discount overridden by incoming calculated value' );
142
143
# Test LSL (Library Sub-Location) field extraction from GIR segments
144
my $mock_line_data = {
145
    GIR => [
146
        {
147
            copy              => '001',
148
            sub_location_code => 'FICTION',    # LSL field
149
            sequence_code     => 'ADULT',      # LSQ field
150
            branch            => 'MAIN'
151
        },
152
        {
153
            copy              => '002',
154
            sub_location_code => 'REFERENCE',    # LSL field
155
            branch            => 'BRANCH2'
156
157
                # sequence_code missing for this item
158
        }
159
    ]
160
};
161
162
my $mock_line = bless $mock_line_data, 'Koha::Edifact::Line';
163
164
# Test LSL field access via girfield method
165
$y = $mock_line->girfield('sub_location_code');
166
is( $y, 'FICTION', 'LSL field (sub_location_code) returned for first occurrence' );
167
168
$y = $mock_line->girfield( 'sub_location_code', 0 );
169
is( $y, 'FICTION', 'LSL field returned for explicit occurrence 0' );
170
171
$y = $mock_line->girfield( 'sub_location_code', 1 );
172
is( $y, 'REFERENCE', 'LSL field returned for occurrence 1' );
173
174
$y = $mock_line->girfield( 'sub_location_code', 2 );
175
is( $y, undef, 'LSL field returns undef for non-existent occurrence' );
176
177
# Test that both LSL and LSQ can coexist
178
$y = $mock_line->girfield( 'sequence_code', 0 );
179
is( $y, 'ADULT', 'LSQ field still works when LSL is present' );
180
181
$y = $mock_line->girfield( 'sequence_code', 1 );
182
is( $y, undef, 'LSQ field correctly returns undef when not present for occurrence' );
183
184
# Test LSL field when LSQ is missing
185
$y = $mock_line->girfield( 'sub_location_code', 1 );
186
is( $y, 'REFERENCE', 'LSL field works correctly when LSQ is missing for that occurrence' );
(-)a/t/db_dependent/Koha/EDI.t (-1 / +115 lines)
Lines 21-27 use Modern::Perl; Link Here
21
use FindBin qw( $Bin );
21
use FindBin qw( $Bin );
22
22
23
use Test::NoWarnings;
23
use Test::NoWarnings;
24
use Test::More tests => 5;
24
use Test::More tests => 6;
25
use Test::MockModule;
25
use Test::MockModule;
26
26
27
use t::lib::Mocks;
27
use t::lib::Mocks;
Lines 976-978 subtest 'create_edi_order_logging' => sub { Link Here
976
976
977
    $schema->storage->txn_rollback;
977
    $schema->storage->txn_rollback;
978
};
978
};
979
980
subtest 'LSL and LSQ validation functions' => sub {
981
    plan tests => 16;
982
983
    $schema->storage->txn_begin;
984
985
    # Mock quote message object for testing
986
    {
987
988
        package MockQuoteMessage;
989
990
        sub new {
991
            my $class = shift;
992
            return bless { errors => [] }, $class;
993
        }
994
995
        sub add_to_edifact_errors {
996
            my ( $self, $error ) = @_;
997
            push @{ $self->{errors} }, $error;
998
        }
999
    }
1000
1001
    # Create test authorised values
1002
    my $loc_av = $builder->build(
1003
        {
1004
            source => 'AuthorisedValue',
1005
            value  => {
1006
                category         => 'LOC',
1007
                authorised_value => 'FICTION',
1008
                lib              => 'Fiction Section'
1009
            }
1010
        }
1011
    );
1012
1013
    my $ccode_av = $builder->build(
1014
        {
1015
            source => 'AuthorisedValue',
1016
            value  => {
1017
                category         => 'CCODE',
1018
                authorised_value => 'ADULT',
1019
                lib              => 'Adult Collection'
1020
            }
1021
        }
1022
    );
1023
1024
    my $quote_message = MockQuoteMessage->new();
1025
1026
    # Test valid location code validation
1027
    ok(
1028
        Koha::EDI::_validate_location_code( 'FICTION', $quote_message ),
1029
        'Valid location code passes validation'
1030
    );
1031
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for valid location code' );
1032
1033
    # Test invalid location code validation
1034
    ok(
1035
        !Koha::EDI::_validate_location_code( 'INVALID_LOC', $quote_message ),
1036
        'Invalid location code fails validation'
1037
    );
1038
    is( scalar @{ $quote_message->{errors} }, 1, 'One error logged for invalid location code' );
1039
    like(
1040
        $quote_message->{errors}->[0]->{details}, qr/Invalid location code 'INVALID_LOC'/,
1041
        'Error details contain correct location code'
1042
    );
1043
1044
    # Reset errors for collection code tests
1045
    $quote_message = MockQuoteMessage->new();
1046
1047
    # Test valid collection code validation
1048
    ok(
1049
        Koha::EDI::_validate_collection_code( 'ADULT', $quote_message ),
1050
        'Valid collection code passes validation'
1051
    );
1052
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for valid collection code' );
1053
1054
    # Test invalid collection code validation
1055
    ok(
1056
        !Koha::EDI::_validate_collection_code( 'INVALID_CCODE', $quote_message ),
1057
        'Invalid collection code fails validation'
1058
    );
1059
    is( scalar @{ $quote_message->{errors} }, 1, 'One error logged for invalid collection code' );
1060
    like(
1061
        $quote_message->{errors}->[0]->{details}, qr/Invalid collection code 'INVALID_CCODE'/,
1062
        'Error details contain correct collection code'
1063
    );
1064
1065
    # Test empty/null handling
1066
    $quote_message = MockQuoteMessage->new();
1067
    ok(
1068
        Koha::EDI::_validate_location_code( '', $quote_message ),
1069
        'Empty location code passes validation'
1070
    );
1071
    ok(
1072
        Koha::EDI::_validate_location_code( undef, $quote_message ),
1073
        'Undefined location code passes validation'
1074
    );
1075
    ok(
1076
        Koha::EDI::_validate_collection_code( '', $quote_message ),
1077
        'Empty collection code passes validation'
1078
    );
1079
    ok(
1080
        Koha::EDI::_validate_collection_code( undef, $quote_message ),
1081
        'Undefined collection code passes validation'
1082
    );
1083
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for empty/undefined values' );
1084
1085
    # Test error message format
1086
    $quote_message = MockQuoteMessage->new();
1087
    Koha::EDI::_validate_location_code( 'TEST_ERROR', $quote_message );
1088
    my $error = $quote_message->{errors}->[0];
1089
    is( $error->{section}, 'GIR+LSQ/LSL validation', 'Error has correct section identifier' );
1090
1091
    $schema->storage->txn_rollback;
1092
};
(-)a/t/db_dependent/Koha/Edifact/Order.t (-2 / +134 lines)
Lines 20-26 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 => 4;
23
use Test::More tests => 5;
24
24
25
use Koha::Edifact::Order;
25
use Koha::Edifact::Order;
26
26
Lines 138-143 subtest 'order_line() tests' => sub { Link Here
138
    # Set EdifactLSQ field to default
138
    # Set EdifactLSQ field to default
139
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'location' );
139
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'location' );
140
140
141
    # Ensure EdifactLSL is empty to maintain backwards compatibility
142
    t::lib::Mocks::mock_preference( 'EdifactLSL', '' );
143
141
    $order->basket->create_items('ordering')->store;
144
    $order->basket->create_items('ordering')->store;
142
    is(
145
    is(
143
        $edi_order->order_line( 1, $orders[0] ),
146
        $edi_order->order_line( 1, $orders[0] ),
Lines 217-222 subtest 'order_line() tests' => sub { Link Here
217
    # Set EdifactLSQ field to ccode
220
    # Set EdifactLSQ field to ccode
218
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'ccode' );
221
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'ccode' );
219
222
223
    # Ensure EdifactLSL is empty to maintain backwards compatibility
224
    t::lib::Mocks::mock_preference( 'EdifactLSL', '' );
225
220
    $order->basket->create_items('ordering')->store;
226
    $order->basket->create_items('ordering')->store;
221
    is(
227
    is(
222
        $edi_order->order_line( 1, $orders[0] ),
228
        $edi_order->order_line( 1, $orders[0] ),
Lines 280-282 subtest 'filename() tests' => sub { Link Here
280
286
281
    $schema->storage->txn_rollback;
287
    $schema->storage->txn_rollback;
282
};
288
};
283
- 
289
290
subtest 'gir_segments() with LSL and LSQ preferences' => sub {
291
    plan tests => 20;
292
293
    $schema->storage->txn_begin;
294
295
    # Test LSL and LSQ preferences
296
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'location' );
297
    t::lib::Mocks::mock_preference( 'EdifactLSL', 'ccode' );
298
299
    # Create test items with both location and ccode
300
    my @test_items = (
301
        {
302
            branchcode     => 'BRANCH1',
303
            itype          => 'BOOK',
304
            itemcallnumber => 'CALL1',
305
            location       => 'FICTION',    # Will be used for LSQ
306
            ccode          => 'ADULT',      # Will be used for LSL
307
        },
308
        {
309
            branchcode     => 'BRANCH2',
310
            itype          => 'DVD',
311
            itemcallnumber => 'CALL2',
312
            location       => 'MEDIA',      # Will be used for LSQ
313
            ccode          => 'CHILD',      # Will be used for LSL
314
        }
315
    );
316
317
    my $params = {
318
        ol_fields => { budget_code => 'FUND123' },
319
        items     => \@test_items
320
    };
321
322
    my @segments = Koha::Edifact::Order::gir_segments($params);
323
324
    ok( scalar @segments >= 2, 'At least two segments created for two items' );
325
326
    # Check first item's GIR segment (segments are strings in EDI format)
327
    my $first_gir = $segments[0];
328
    ok( $first_gir, 'First segment exists' );
329
330
    # Check that the segment contains expected data
331
    like( $first_gir, qr/GIR/,         'Segment contains GIR tag' );
332
    like( $first_gir, qr/FUND123:LFN/, 'Budget code included in first segment' );
333
    like( $first_gir, qr/BRANCH1:LLO/, 'Branch code included in first segment' );
334
    like( $first_gir, qr/BOOK:LST/,    'Item type included in first segment' );
335
    like( $first_gir, qr/FICTION:LSQ/, 'LSQ field contains location value' );
336
    like( $first_gir, qr/ADULT:LSL/,   'LSL field contains collection code value' );
337
338
    # Test reversed preferences
339
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'ccode' );       # LSQ -> collection
340
    t::lib::Mocks::mock_preference( 'EdifactLSL', 'location' );    # LSL -> location
341
342
    my @test_items_rev = (
343
        {
344
            branchcode     => 'BRANCH3',
345
            itype          => 'BOOK',
346
            itemcallnumber => 'CALL3',
347
            location       => 'REFERENCE',    # Will be used for LSL
348
            ccode          => 'RARE',         # Will be used for LSQ
349
        }
350
    );
351
352
    my $params_rev = {
353
        ol_fields => { budget_code => 'FUND456' },
354
        items     => \@test_items_rev
355
    };
356
357
    @segments = Koha::Edifact::Order::gir_segments($params_rev);
358
    my $gir_rev = $segments[0];
359
360
    # Check that the segment contains expected reversed mappings
361
    like( $gir_rev, qr/RARE:LSQ/,      'LSQ field contains collection code when preference is ccode' );
362
    like( $gir_rev, qr/REFERENCE:LSL/, 'LSL field contains location when preference is location' );
363
364
    # Test with one preference empty
365
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'location' );
366
    t::lib::Mocks::mock_preference( 'EdifactLSL', '' );           # Empty = ignore
367
368
    @segments = Koha::Edifact::Order::gir_segments($params);
369
    my $gir_partial = $segments[0];
370
371
    like( $gir_partial, qr/FICTION:LSQ/, 'LSQ field included when preference is set' );
372
    unlike( $gir_partial, qr/:LSL/, 'LSL field not included when preference is empty' );
373
374
    # Test with both preferences empty
375
    t::lib::Mocks::mock_preference( 'EdifactLSQ', '' );
376
    t::lib::Mocks::mock_preference( 'EdifactLSL', '' );
377
378
    @segments = Koha::Edifact::Order::gir_segments($params);
379
    my $gir_empty = $segments[0];
380
381
    unlike( $gir_empty, qr/:LSQ/, 'LSQ field not included when preference is empty' );
382
    unlike( $gir_empty, qr/:LSL/, 'LSL field not included when preference is empty' );
383
384
    # Test with LSQ empty but LSL set
385
    t::lib::Mocks::mock_preference( 'EdifactLSQ', '' );         # Empty = ignore
386
    t::lib::Mocks::mock_preference( 'EdifactLSL', 'ccode' );    # LSL -> collection
387
388
    @segments = Koha::Edifact::Order::gir_segments($params);
389
    my $gir_lsl_only = $segments[0];
390
391
    unlike( $gir_lsl_only, qr/:LSQ/, 'LSQ field not included when preference is empty' );
392
    like( $gir_lsl_only, qr/ADULT:LSL/, 'LSL field included when preference is set' );
393
394
    # Test with both preferences set to same field (location)
395
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'location' );    # LSQ -> location
396
    t::lib::Mocks::mock_preference( 'EdifactLSL', 'location' );    # LSL -> location
397
398
    @segments = Koha::Edifact::Order::gir_segments($params);
399
    my $gir_both_location = $segments[0];
400
401
    like( $gir_both_location, qr/FICTION:LSQ/, 'LSQ field contains location value when both map to location' );
402
    like( $gir_both_location, qr/FICTION:LSL/, 'LSL field contains location value when both map to location' );
403
404
    # Test with both preferences set to same field (ccode)
405
    t::lib::Mocks::mock_preference( 'EdifactLSQ', 'ccode' );       # LSQ -> collection
406
    t::lib::Mocks::mock_preference( 'EdifactLSL', 'ccode' );       # LSL -> collection
407
408
    @segments = Koha::Edifact::Order::gir_segments($params);
409
    my $gir_both_ccode = $segments[0];
410
411
    like( $gir_both_ccode, qr/ADULT:LSQ/, 'LSQ field contains collection code value when both map to ccode' );
412
    like( $gir_both_ccode, qr/ADULT:LSL/, 'LSL field contains collection code value when both map to ccode' );
413
414
    $schema->storage->txn_rollback;
415
};

Return to bug 40391