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 977-979 subtest 'create_edi_order_logging' => sub { Link Here
977
977
978
    $schema->storage->txn_rollback;
978
    $schema->storage->txn_rollback;
979
};
979
};
980
981
subtest 'LSL and LSQ validation functions' => sub {
982
    plan tests => 16;
983
984
    $schema->storage->txn_begin;
985
986
    # Mock quote message object for testing
987
    {
988
989
        package MockQuoteMessage;
990
991
        sub new {
992
            my $class = shift;
993
            return bless { errors => [] }, $class;
994
        }
995
996
        sub add_to_edifact_errors {
997
            my ( $self, $error ) = @_;
998
            push @{ $self->{errors} }, $error;
999
        }
1000
    }
1001
1002
    # Create test authorised values
1003
    my $loc_av = $builder->build(
1004
        {
1005
            source => 'AuthorisedValue',
1006
            value  => {
1007
                category         => 'LOC',
1008
                authorised_value => 'FICTION',
1009
                lib              => 'Fiction Section'
1010
            }
1011
        }
1012
    );
1013
1014
    my $ccode_av = $builder->build(
1015
        {
1016
            source => 'AuthorisedValue',
1017
            value  => {
1018
                category         => 'CCODE',
1019
                authorised_value => 'ADULT',
1020
                lib              => 'Adult Collection'
1021
            }
1022
        }
1023
    );
1024
1025
    my $quote_message = MockQuoteMessage->new();
1026
1027
    # Test valid location code validation
1028
    ok(
1029
        Koha::EDI::_validate_location_code( 'FICTION', $quote_message ),
1030
        'Valid location code passes validation'
1031
    );
1032
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for valid location code' );
1033
1034
    # Test invalid location code validation
1035
    ok(
1036
        !Koha::EDI::_validate_location_code( 'INVALID_LOC', $quote_message ),
1037
        'Invalid location code fails validation'
1038
    );
1039
    is( scalar @{ $quote_message->{errors} }, 1, 'One error logged for invalid location code' );
1040
    like(
1041
        $quote_message->{errors}->[0]->{details}, qr/Invalid location code 'INVALID_LOC'/,
1042
        'Error details contain correct location code'
1043
    );
1044
1045
    # Reset errors for collection code tests
1046
    $quote_message = MockQuoteMessage->new();
1047
1048
    # Test valid collection code validation
1049
    ok(
1050
        Koha::EDI::_validate_collection_code( 'ADULT', $quote_message ),
1051
        'Valid collection code passes validation'
1052
    );
1053
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for valid collection code' );
1054
1055
    # Test invalid collection code validation
1056
    ok(
1057
        !Koha::EDI::_validate_collection_code( 'INVALID_CCODE', $quote_message ),
1058
        'Invalid collection code fails validation'
1059
    );
1060
    is( scalar @{ $quote_message->{errors} }, 1, 'One error logged for invalid collection code' );
1061
    like(
1062
        $quote_message->{errors}->[0]->{details}, qr/Invalid collection code 'INVALID_CCODE'/,
1063
        'Error details contain correct collection code'
1064
    );
1065
1066
    # Test empty/null handling
1067
    $quote_message = MockQuoteMessage->new();
1068
    ok(
1069
        Koha::EDI::_validate_location_code( '', $quote_message ),
1070
        'Empty location code passes validation'
1071
    );
1072
    ok(
1073
        Koha::EDI::_validate_location_code( undef, $quote_message ),
1074
        'Undefined location code passes validation'
1075
    );
1076
    ok(
1077
        Koha::EDI::_validate_collection_code( '', $quote_message ),
1078
        'Empty collection code passes validation'
1079
    );
1080
    ok(
1081
        Koha::EDI::_validate_collection_code( undef, $quote_message ),
1082
        'Undefined collection code passes validation'
1083
    );
1084
    is( scalar @{ $quote_message->{errors} }, 0, 'No errors for empty/undefined values' );
1085
1086
    # Test error message format
1087
    $quote_message = MockQuoteMessage->new();
1088
    Koha::EDI::_validate_location_code( 'TEST_ERROR', $quote_message );
1089
    my $error = $quote_message->{errors}->[0];
1090
    is( $error->{section}, 'GIR+LSQ/LSL validation', 'Error has correct section identifier' );
1091
1092
    $schema->storage->txn_rollback;
1093
};
(-)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