Bugzilla – Attachment 184488 Details for
Bug 40383
Modernise the EDIFACT Message display modal
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40383: Add JSON representation to Koha::Edifact and JSON download to edimsg.pl
Bug-40383-Add-JSON-representation-to-KohaEdifact-a.patch (text/plain), 9.33 KB, created by
Martin Renvoize (ashimema)
on 2025-07-22 16:17:59 UTC
(
hide
)
Description:
Bug 40383: Add JSON representation to Koha::Edifact and JSON download to edimsg.pl
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-07-22 16:17:59 UTC
Size:
9.33 KB
patch
obsolete
>From d6b1ee613f5061ac9014086a347840b7a98e5dfe Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Tue, 22 Jul 2025 14:08:59 +0100 >Subject: [PATCH] Bug 40383: Add JSON representation to Koha::Edifact and JSON > download to edimsg.pl > >This patch implements a JSON representation of EDIFACT interchanges for enhanced >programmatic access and debugging capabilities. > >Backend Changes: >- Add to_json() method to Koha::Edifact module >- Structured JSON output with header, messages array, and trailer >- Segment parsing with raw data, elements arrays, and line_id tracking >- Line item grouping using LIN segment identifiers > >Frontend Changes: >- Add JSON download button to edimsg.pl page >- Support for ?format=json parameter and Accept: application/json header >- Proper HTTP content-type handling for JSON responses >- Error handling for missing messages in JSON format > >JSON Structure: >{ > "header": "UNB+UNOC:3+...", > "messages": [ > { > "header": "UNH+1+QUOTES:D:93A:UN:EAN008'", > "segments": [ > { > "tag": "LIN", > "raw": "LIN+1+1+9780552150040:EN'", > "elements": ["1", "1", "9780552150040:EN"], > "line_id": "1" > } > ], > "trailer": "UNT+25+1'" > } > ], > "trailer": "UNZ+1+1'" >} > >Test plan: >1. Apply this patch >2. Ensure you have EDIFACT messages in your system >3. Go to Acquisitions > EDIFACT messages >4. Click "View message" for any message >5. Click the new "JSON" button >6. Verify JSON downloads with proper structure >7. Verify direct URL access with ?format=json parameter works >8. Test with Accept: application/json header >--- > Koha/Edifact.pm | 115 ++++++++++++++++++ > acqui/edimsg.pl | 37 +++++- > .../prog/en/modules/acqui/edimsg.tt | 7 ++ > 3 files changed, 155 insertions(+), 4 deletions(-) > >diff --git a/Koha/Edifact.pm b/Koha/Edifact.pm >index 7479a9b42b5..5985c1ff77d 100644 >--- a/Koha/Edifact.pm >+++ b/Koha/Edifact.pm >@@ -21,6 +21,7 @@ use strict; > use warnings; > use File::Slurp qw( read_file ); > use Carp qw( carp croak ); >+use JSON qw( encode_json ); > use Koha::Edifact::Segment; > use Koha::Edifact::Message; > >@@ -172,6 +173,113 @@ sub message_array { > return $msg_arr; > } > >+sub to_json { >+ my $self = shift; >+ >+ # Find interchange header (UNB) >+ my $header_seg; >+ my $trailer_seg; >+ my @all_segments = @{ $self->{transmission} }; >+ >+ # Get header and trailer >+ for my $i ( 0 .. $#all_segments ) { >+ if ( $all_segments[$i]->tag eq 'UNB' ) { >+ $header_seg = $all_segments[$i]; >+ } elsif ( $all_segments[$i]->tag eq 'UNZ' ) { >+ $trailer_seg = $all_segments[$i]; >+ } >+ } >+ >+ # Build messages array >+ my @json_messages; >+ my $current_message; >+ my @current_segments; >+ my $current_line_id; >+ >+ for my $segment (@all_segments) { >+ my $tag = $segment->tag; >+ >+ if ( $tag eq 'UNH' ) { >+ >+ # Start new message >+ if ($current_message) { >+ $current_message->{segments} = [@current_segments]; >+ push @json_messages, $current_message; >+ } >+ $current_message = { >+ header => $segment->as_string, >+ segments => [], >+ }; >+ @current_segments = (); >+ $current_line_id = undef; >+ } elsif ( $tag eq 'UNT' ) { >+ >+ # End current message >+ if ($current_message) { >+ $current_message->{trailer} = $segment->as_string; >+ $current_message->{segments} = [@current_segments]; >+ push @json_messages, $current_message; >+ } >+ $current_message = undef; >+ @current_segments = (); >+ $current_line_id = undef; >+ } elsif ( $tag eq 'UNB' || $tag eq 'UNZ' ) { >+ >+ # Skip - these are handled separately >+ next; >+ } elsif ($current_message) { >+ >+ # Process segment within message >+ my $segment_data = { >+ tag => $tag, >+ raw => $segment->as_string, >+ elements => [], >+ }; >+ >+ # Extract elements >+ my $elem_count = 0; >+ while ( defined( my $elem = $segment->elem($elem_count) ) ) { >+ push @{ $segment_data->{elements} }, $elem; >+ $elem_count++; >+ } >+ >+ # Handle line_id assignment >+ if ( $tag eq 'LIN' ) { >+ $current_line_id = $segment->elem(0); >+ $segment_data->{line_id} = $current_line_id if defined $current_line_id; >+ } elsif ( $tag eq 'UNS' ) { >+ >+ # UNS (Section Control) marks transition to message summary >+ # Reset line_id so subsequent segments are treated as message-level >+ $current_line_id = undef; >+ } elsif ( defined $current_line_id && $tag !~ /^(UNH|UNT|UNS|CNT)$/ ) { >+ >+ # Assign line_id to segments that belong to current line item >+ # Exclude message control segments (UNH, UNT, UNS, CNT) >+ # After UNS, current_line_id is undefined, so segments are message-level >+ $segment_data->{line_id} = $current_line_id; >+ } >+ >+ push @current_segments, $segment_data; >+ } >+ } >+ >+ # Handle any remaining message >+ if ($current_message) { >+ $current_message->{segments} = [@current_segments]; >+ push @json_messages, $current_message; >+ } >+ >+ # Build final structure >+ my $json_structure = { >+ header => $header_seg ? $header_seg->as_string : undef, >+ messages => \@json_messages, >+ trailer => $trailer_seg ? $trailer_seg->as_string : undef, >+ }; >+ >+ return encode_json($json_structure); >+} >+ > # > # internal parsing routines used in _init > # >@@ -291,6 +399,13 @@ Edifact - Edifact message handler > > return an array of Message objects contained in the Edifact transmission > >+=head2 to_json >+ >+ returns a JSON representation of the complete edifact interchange. >+ The JSON structure includes the interchange header, all messages with their >+ segments (both raw and parsed), and the interchange trailer. >+ Line items are grouped using line_id extracted from LIN segments. >+ > =head1 Internal Methods > > =head2 _init >diff --git a/acqui/edimsg.pl b/acqui/edimsg.pl >index 8a49359e310..5891d7671e6 100755 >--- a/acqui/edimsg.pl >+++ b/acqui/edimsg.pl >@@ -20,11 +20,18 @@ use Modern::Perl; > > use CGI; > use Koha::Database; >+use Koha::Edifact; > use C4::Koha; > use C4::Auth qw( get_template_and_user ); >-use C4::Output qw( output_html_with_http_headers ); >+use C4::Output qw( output_html_with_http_headers output_with_http_headers ); > > my $q = CGI->new; >+ >+# Check if JSON output is requested >+my $format = $q->param('format') || ''; >+my $accept_header = $ENV{HTTP_ACCEPT} || ''; >+my $wants_json = ( $format eq 'json' ) || ( $accept_header =~ m|application/json| ); >+ > my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user( > { > template_name => 'acqui/edimsg.tt', >@@ -33,17 +40,39 @@ my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user( > flagsrequired => { acquisition => 'edi_manage' }, > } > ); >+ > my $msg_id = $q->param('id'); > my $schema = Koha::Database->new()->schema(); > > my $msg = $schema->resultset('EdifactMessage')->find($msg_id); >+ > if ($msg) { > my $transmission = $msg->raw_msg; > >- my @segments = segmentize($transmission); >- $template->param( segments => \@segments ); >+ if ($wants_json) { >+ >+ # Return JSON representation using Koha::Edifact >+ my $edifact = Koha::Edifact->new( { transmission => $transmission } ); >+ my $json_output = $edifact->to_json(); >+ >+ output_with_http_headers( $q, $cookie, $json_output, 'json', '200 OK' ); >+ exit; >+ } else { >+ >+ # Return HTML representation (existing behavior) >+ my @segments = segmentize($transmission); >+ $template->param( >+ segments => \@segments, >+ id => $msg_id >+ ); >+ } > } else { >- $template->param( no_message => 1 ); >+ if ($wants_json) { >+ output_with_http_headers( $q, $cookie, '{"error":"Message not found"}', 'json', '404 Not Found' ); >+ exit; >+ } else { >+ $template->param( no_message => 1 ); >+ } > } > > output_html_with_http_headers( $q, $cookie, $template->output ); >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/edimsg.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/edimsg.tt >index 0f4a85e1419..eafc8927aee 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/edimsg.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/edimsg.tt >@@ -32,6 +32,13 @@ > [% IF no_message %] > <div class="alert alert-info">The requested message cannot be displayed</div> > [% ELSE %] >+ <div class="row"> >+ <div class="col-sm-2"> >+ <div id="toolbar" class="btn-toolbar"> >+ <a class="btn btn-default btn-sm" href="[% "/cgi-bin/koha/acqui/edimsg.pl?id=" _ id _ "&format=json" %]" target="_blank"> <i class="fa fa-download"></i> JSON </a> >+ </div> >+ </div> >+ </div> > <ul> > [% FOREACH seg IN segments %] > <li>[% seg | html %]</li> >-- >2.50.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 40383
:
184185
|
184487
| 184488 |
184489
|
184490