Bug 30144: Add unit tests for servicing instructions

This patch adds comprehensive unit tests for the servicing instruction
functionality in t/db_dependent/Koha/Edifact/Order.t.

Changes:
- Updated test count from 6 to 7
- Added servicing_instruction => undef to test orders to prevent
  TestBuilder from generating random invalid JSON
- Added servicing instruction subtest with 18 tests covering:
  * Single LVC instruction
  * Single LVT instruction
  * Multiple LVC in one group (tests GIR segment overflow)
  * Mixed LVC/LVT in one group
  * Multiple groups
  * Empty servicing instruction
  * Invalid JSON handling (logged to EDI log)
- Tests correctly handle GIR segment 5-element limit and overflow
  to additional segments

Test plan:
1. Run: prove t/db_dependent/Koha/Edifact/Order.t
2. Verify all tests pass

Sponsored-by: Martin Renvoize <martin.renvoize@gmail.com>
Signed-off-by: Hannah Dunne-Howrie <hdunne-howrie@westminster.gov.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This commit is contained in:
Martin Renvoize 2026-02-12 18:24:59 +00:00 committed by Pedro Amorim
parent c215f2dd43
commit b02cd5e1fe
No known key found for this signature in database
GPG Key ID: 06B75BA7F3894D55
1 changed files with 267 additions and 6 deletions

View File

@ -20,11 +20,13 @@
use Modern::Perl;
use Test::NoWarnings;
use Test::More tests => 6;
use Test::More tests => 7;
use Koha::Edifact::Order;
use JSON qw( encode_json );
use t::lib::Mocks;
use t::lib::Mocks::Logger;
use t::lib::TestBuilder;
my $schema = Koha::Database->new->schema;
@ -122,11 +124,12 @@ subtest 'order_line() tests' => sub {
{
class => 'Koha::Acquisition::Orders',
value => {
biblionumber => $biblio->biblionumber,
quantity => 2,
line_item_id => 'EDILINEID1',
order_vendornote => 'A not so pretty note',
listprice => '1.50'
biblionumber => $biblio->biblionumber,
quantity => 2,
line_item_id => 'EDILINEID1',
order_vendornote => 'A not so pretty note',
listprice => '1.50',
servicing_instruction => undef
}
}
);
@ -613,3 +616,261 @@ subtest 'gir_segments() with LSL and LSQ preferences' => sub {
$schema->storage->txn_rollback;
};
subtest 'gir_segments() with servicing instructions' => sub {
plan tests => 30;
$schema->storage->txn_begin;
my $logger = t::lib::Mocks::Logger->new();
# Test 1: Single LVC instruction
my $params_lvc = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json( [ [ { type => 'LVC', value => 'BB' } ] ] )
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
my @segments = Koha::Edifact::Order::gir_segments($params_lvc);
ok( scalar @segments >= 1, 'Segment created with LVC servicing instruction' );
like( $segments[0], qr/BB:LVC/, 'LVC servicing instruction included in GIR segment' );
# Test 2: Single LVT instruction
my $params_lvt = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json( [ [ { type => 'LVT', value => 'Special handling required' } ] ] )
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_lvt);
ok( scalar @segments >= 1, 'Segment created with LVT servicing instruction' );
like(
$segments[0], qr/Special handling required:LVT/,
'LVT servicing instruction included in GIR segment'
);
# Test 3: Multiple LVC instructions in one group
my $params_multi_lvc = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction =>
encode_json( [ [ { type => 'LVC', value => 'BB' }, { type => 'LVC', value => 'BI' } ] ] )
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_multi_lvc);
ok( scalar @segments >= 2, 'Multiple segments created when exceeding 5 elements' );
like( $segments[0], qr/BB:LVC/, 'First LVC instruction in first segment' );
like( $segments[1], qr/BI:LVC/, 'Second LVC instruction in second segment (overflow)' );
# Test 4: Mixed LVC and LVT in one group
my $params_mixed = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json(
[
[
{ type => 'LVC', value => 'BB' },
{ type => 'LVT', value => 'Apply on spine only' }
]
]
)
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_mixed);
ok( scalar @segments >= 2, 'Multiple segments created with mixed LVC/LVT instructions' );
like( $segments[0], qr/BB:LVC/, 'LVC instruction in first segment' );
like( $segments[1], qr/Apply on spine only:LVT/, 'LVT instruction in second segment (overflow)' );
# Test 5: Multiple groups
my $params_multi_groups = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json(
[
[ { type => 'LVC', value => 'BB' }, { type => 'LVT', value => 'Spine label' } ],
[ { type => 'LVC', value => 'BI' } ],
]
)
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_multi_groups);
ok( scalar @segments >= 2, 'Multiple segments created with multiple servicing groups' );
# With 4 item fields + 3 servicing instructions = 7 elements, we'll have overflow
like( $segments[0], qr/BB:LVC/, 'First group LVC in first segment' );
like( $segments[1], qr/Spine label:LVT/, 'First group LVT in second segment (overflow)' );
like( $segments[1], qr/BI:LVC/, 'Second group LVC in second segment' );
# Test 6: Empty servicing instruction
my $params_empty = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => undef
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_empty);
ok( scalar @segments >= 1, 'Segment created without servicing instruction' );
unlike( $segments[0], qr/:LVC/, 'No LVC instruction when servicing_instruction is empty' );
unlike( $segments[0], qr/:LVT/, 'No LVT instruction when servicing_instruction is empty' );
# Test 7: Invalid JSON (should log error but not crash)
my $params_invalid = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => 'not valid json'
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
# Invalid JSON is logged to EDI log but doesn't crash
$logger->clear;
@segments = Koha::Edifact::Order::gir_segments($params_invalid);
ok( scalar @segments >= 1, 'Segment created even with invalid JSON (degrades gracefully)' );
$logger->warn_like(
qr/Failed to parse servicing_instruction JSON/,
'A warning is logged when servicing_instruction JSON cannot be parsed'
);
# Test 8: More than 10 GIR elements require a third segment. This is the
# regression test for the e_cnt reset fix: without resetting e_cnt when a
# new segment starts, e_cnt free-runs past 5 and never equals 5 again, so
# every element past the first split piles into a single second segment
# instead of being split again at the 10th element.
my $params_many_elements = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json(
[
[ { type => 'LVC', value => 'BB' } ],
[ { type => 'LVC', value => 'BI' } ],
[ { type => 'LVC', value => 'BC' } ],
[ { type => 'LVC', value => 'CA' } ],
[ { type => 'LVC', value => 'JK' } ],
[ { type => 'LVC', value => 'KA' } ],
[ { type => 'LVC', value => 'LA' } ],
]
)
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
# budget_code + branchcode + itype + itemcallnumber + 7 LVCs = 11 elements
@segments = Koha::Edifact::Order::gir_segments($params_many_elements);
is( scalar @segments, 3, 'Exactly 3 GIR segments created for 11 elements (5 + 5 + 1)' );
like( $segments[1], qr/BI:LVC/, 'Second segment contains an element from the second batch of 5' );
like( $segments[1], qr/KA:LVC/, 'Second segment contains the last element of the second batch of 5' );
unlike( $segments[1], qr/LA:LVC/, 'Second segment does not contain the 11th element' );
like( $segments[2], qr/LA:LVC/, 'Third segment contains the 11th (overflow) element on its own' );
# Test 9: A group with more than 2 instructions is not capped server-side;
# every valid instruction is still flattened into GIR elements
my $params_oversized_group = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json(
[
[
{ type => 'LVC', value => 'BB' },
{ type => 'LVC', value => 'BI' },
{ type => 'LVT', value => 'Extra free text' }
]
]
)
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_oversized_group);
my $all_segments = join q{}, @segments;
like( $all_segments, qr/BB:LVC/, 'First instruction in an oversized group is included' );
like( $all_segments, qr/BI:LVC/, 'Second instruction in an oversized group is included' );
like( $all_segments, qr/Extra free text:LVT/, 'Third instruction in an oversized group is included' );
# Test 10: An empty servicing instruction group produces no GIR elements
my $params_empty_group = {
ol_fields => {
budget_code => 'FUND123',
servicing_instruction => encode_json( [ [] ] )
},
items => [
{
branchcode => 'BRANCH1',
itype => 'BOOK',
itemcallnumber => 'CALL1',
}
]
};
@segments = Koha::Edifact::Order::gir_segments($params_empty_group);
ok( scalar @segments >= 1, 'Segment created with an empty servicing instruction group' );
unlike( $segments[0], qr/:LVC/, 'No LVC instruction from an empty group' );
unlike( $segments[0], qr/:LVT/, 'No LVT instruction from an empty group' );
$schema->storage->txn_rollback;
};