Bug 30144: Process and send servicing instructions in EDI messages
This patch updates the EDIFACT processing to handle multiple servicing
instruction groups in both incoming quotes and outgoing orders.
Changes to Koha/EDI.pm (quote_item):
- Reads both LVC (coded) and LVT (freetext) instructions from incoming quotes
- Validates LVC codes against EDIFACT_SI authorized values
- Stores instructions as JSON array structure
- Groups instructions that work together
Changes to Koha/Edifact/Order.pm (gir_segments):
- Parses JSON servicing instruction data from order
- Generates multiple GIR segments for outgoing orders
- Each instruction becomes a separate GIR element
- Logs JSON parse errors to EDI log using Koha::Logger
- Fixed element counter reset bug when segments exceed 5 elements
Structure allows vendors to specify:
- Single coded instruction: [[{type:"LVC",value:"BB"}]]
- Single text instruction: [[{type:"LVT",value:"Handle with care"}]]
- Combined instructions: [[{type:"LVC",value:"BB"},{type:"LVT",value:"Apply on spine"}]]
- Multiple services: [[{type:"LVC",value:"BB"}],[{type:"LVC",value:"BI"}]]
Test plan:
1. Receive EDIFACT quote with servicing instructions
2. Verify instructions are stored correctly in aqorders
3. Create EDI order from basket
4. Verify GIR segments are generated correctly in outgoing message
5. Check EDI log for any JSON parse errors
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:
parent
8d1e208a7b
commit
4f2829c639
52
Koha/EDI.pm
52
Koha/EDI.pm
|
|
@ -34,6 +34,7 @@ use utf8;
|
|||
use English qw{ -no_match_vars };
|
||||
use Business::ISBN;
|
||||
use DateTime;
|
||||
use JSON qw( encode_json );
|
||||
use C4::Context;
|
||||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
|
|
@ -958,17 +959,50 @@ sub quote_item {
|
|||
$order_hash->{line_item_id} = $item->item_number_id;
|
||||
}
|
||||
|
||||
if ( $item->girfield('servicing_instruction') ) {
|
||||
my $occ = 0;
|
||||
my $txt = q{};
|
||||
my $si;
|
||||
while ( $si = $item->girfield( 'servicing_instruction', $occ ) ) {
|
||||
if ($occ) {
|
||||
$txt .= q{: };
|
||||
# Extract servicing instructions (LVT freetext and/or LVC coded)
|
||||
# Build JSON array structure: [[{type,value},...]]
|
||||
my @servicing_groups;
|
||||
my @current_group;
|
||||
|
||||
# Read LVC (coded) instructions
|
||||
my $occ = 0;
|
||||
my $lvc_val;
|
||||
while ( $lvc_val = $item->girfield( 'coded_servicing_instruction', $occ ) ) {
|
||||
|
||||
# Validate against EDIFACT_SI authorized values
|
||||
my $av = Koha::AuthorisedValues->find(
|
||||
{
|
||||
category => 'EDIFACT_SI',
|
||||
authorised_value => $lvc_val
|
||||
}
|
||||
$txt .= $si;
|
||||
++$occ;
|
||||
);
|
||||
if ($av) {
|
||||
push @current_group, { type => 'LVC', value => $lvc_val };
|
||||
} else {
|
||||
$quote_message->add_to_edifact_errors(
|
||||
{
|
||||
section => "GIR+LVC validation",
|
||||
details =>
|
||||
"Invalid servicing instruction code '$lvc_val' - not found in EDIFACT_SI authorized values"
|
||||
}
|
||||
);
|
||||
$logger->trace("Invalid servicing instruction code: $lvc_val");
|
||||
}
|
||||
++$occ;
|
||||
}
|
||||
|
||||
# Read LVT (freetext) instructions
|
||||
$occ = 0;
|
||||
my $lvt_val;
|
||||
while ( $lvt_val = $item->girfield( 'servicing_instruction', $occ ) ) {
|
||||
push @current_group, { type => 'LVT', value => $lvt_val };
|
||||
++$occ;
|
||||
}
|
||||
|
||||
# Store as JSON if we have any instructions
|
||||
if (@current_group) {
|
||||
push @servicing_groups, \@current_group;
|
||||
$order_hash->{servicing_instruction} = encode_json( \@servicing_groups );
|
||||
}
|
||||
if ($order_note) {
|
||||
$order_hash->{order_vendornote} = $order_note;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ use DateTime;
|
|||
use Readonly qw( Readonly );
|
||||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use C4::Budgets qw( GetBudget );
|
||||
use Koha::Logger;
|
||||
use C4::Budgets qw( GetBudget );
|
||||
use JSON qw( decode_json );
|
||||
|
||||
use Koha::Acquisition::Orders;
|
||||
|
||||
|
|
@ -432,7 +434,10 @@ sub order_line {
|
|||
}
|
||||
}
|
||||
my $budget = GetBudget( $orderline->budget_id );
|
||||
my $ol_fields = { budget_code => $budget->{budget_code}, };
|
||||
my $ol_fields = {
|
||||
budget_code => $budget->{budget_code},
|
||||
servicing_instruction => $orderline->servicing_instruction,
|
||||
};
|
||||
|
||||
my $item_fields = [];
|
||||
for my $item (@items) {
|
||||
|
|
@ -616,13 +621,38 @@ sub gir_segments {
|
|||
{ identity_number => 'LSM', data => encode_text( $item->{itemcallnumber} ) };
|
||||
}
|
||||
|
||||
# itemcallnumber -> shelfmark
|
||||
# Servicing instructions (LVT freetext and/or LVC coded)
|
||||
# Format: JSON array of arrays: [[{type,value},...],[{type,value},...]]
|
||||
# Each inner array is a group of instructions that work together
|
||||
if ( $orderfields->{servicing_instruction} ) {
|
||||
push @gir_elements,
|
||||
{
|
||||
identity_number => 'LVT',
|
||||
data => encode_text( $orderfields->{servicing_instruction} )
|
||||
};
|
||||
my $si_data = $orderfields->{servicing_instruction};
|
||||
my $servicing_groups;
|
||||
|
||||
eval { $servicing_groups = decode_json($si_data); };
|
||||
if ($@) {
|
||||
my $logger = Koha::Logger->get( { interface => 'edi' } );
|
||||
$logger->warn("Failed to parse servicing_instruction JSON: $@");
|
||||
}
|
||||
|
||||
# Add all servicing instruction groups
|
||||
if ( ref $servicing_groups eq 'ARRAY' ) {
|
||||
foreach my $group (@$servicing_groups) {
|
||||
if ( ref $group eq 'ARRAY' ) {
|
||||
foreach my $instruction (@$group) {
|
||||
if ( ref $instruction eq 'HASH'
|
||||
&& $instruction->{type}
|
||||
&& $instruction->{value} )
|
||||
{
|
||||
push @gir_elements,
|
||||
{
|
||||
identity_number => $instruction->{type},
|
||||
data => encode_text( $instruction->{value} )
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
my $e_cnt = 0; # count number of elements so we dont exceed 5 per segment
|
||||
my $copy_no = sprintf 'GIR+%03d', $sequence_no;
|
||||
|
|
@ -630,7 +660,8 @@ sub gir_segments {
|
|||
foreach my $e (@gir_elements) {
|
||||
if ( $e_cnt == 5 ) {
|
||||
push @segments, $seg;
|
||||
$seg = $copy_no;
|
||||
$seg = $copy_no;
|
||||
$e_cnt = 0;
|
||||
}
|
||||
$seg .=
|
||||
add_gir_identity_number( $e->{identity_number}, $e->{data} );
|
||||
|
|
|
|||
Loading…
Reference in New Issue