Bug 20253: Optionally use buyer's purchase order number from EDIFACT quote as basket name

This enhancement allows libraries to configure vendors to use the buyer's
purchase order number (from RFF+ON segments) as the basket name instead of
the EDIFACT filename, improving searchability and reference tracking.

Backend Changes:
- Added purchase_order_number() method to Koha::Edifact::Message to extract
  RFF+ON segments from message-level data (before first LIN segment)
- Modified process_quote() in Koha::EDI to use purchase order number for
  basket naming when configured, with fallback to filename

Frontend Changes:
- Updated admin/edi_accounts.pl to handle po_is_basketname parameter
- Added "Use purhase order numbers" option to EDI accounts template

Test Plan:
1. Apply patches and run database update
2. Go to Administration > Acquisitions > EDI accounts
3. Create or edit a vendor EDI account
4. Verify "Use purchase order numbers" option appears
5. Enable "Use purchase order numbers" and save
6. Process an EDIFACT quote file that contains RFF+ON segments
7. Verify the created basket name uses the purchase order number instead of filename
8. Process a quote file without RFF+ON segments
9. Verify the basket name falls back to the filename
10. Test with "Use purchase order numbers" disabled
11. Verify basket names use filenames regardless of RFF+ON presence
12. Run tests: prove t/Edifact.t t/db_dependent/Koha/EDI.t

The feature is optional and backward compatible - existing behavior is
unchanged unless explicitly configured.

Signed-off-by: Hannah Dunne-Howrie <hdunne-howrie@westminster.gov.uk>
Sponsored-by: Westminster City Council <https://www.westminster.gov.uk/>
Sponsored-by: Royal Borough of Kensington and Chelsea <https://www.rbkc.gov.uk/>
Sponsored-by: OpenFifth <https://openfifth.co.uk/>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Martin Renvoize 2025-07-08 14:45:19 +01:00 committed by Lucas Gass
parent 168a5a9107
commit 4179211ce8
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
4 changed files with 95 additions and 27 deletions

View File

@ -649,11 +649,29 @@ sub process_quote {
my $split_message;
my @added_baskets; # if auto & multiple baskets need to order all
# Get vendor EDI account configuration
my $v = $schema->resultset('VendorEdiAccount')->search(
{
vendor_id => $quote_message->vendor_id,
}
)->single;
if ( @{$messages} && $quote_message->vendor_id ) {
foreach my $msg ( @{$messages} ) {
++$message_count;
# Determine basket name based on vendor configuration
my $basket_name = $quote_message->filename;
if ( $v && $v->po_is_basketname ) {
my $purchase_order_number = $msg->purchase_order_number;
if ($purchase_order_number) {
$basket_name = $purchase_order_number;
}
}
my $basketno = NewBasket(
$quote_message->vendor_id, 0, $quote_message->filename, q{},
$quote_message->vendor_id, 0, $basket_name, q{},
q{} . q{}
);
push @added_baskets, $basketno;
@ -695,12 +713,7 @@ sub process_quote {
$quote_message->status($status);
$quote_message->update; # status and basketno link
# Do we automatically generate orders for this vendor
my $v = $schema->resultset('VendorEdiAccount')->search(
{
vendor_id => $quote_message->vendor_id,
}
)->single;
if ( $v->auto_orders ) {
if ( $v && $v->auto_orders ) {
for my $i ( 0 .. $#added_baskets ) {
my $basketno = $added_baskets[$i];

View File

@ -183,6 +183,22 @@ sub supplier_ean {
}
sub purchase_order_number {
my $self = shift;
foreach my $s ( @{ $self->{datasegs} } ) {
if ( $s->tag eq 'LIN' ) {
last;
}
if ( $s->tag eq 'RFF' ) {
my $qualifier = $s->elem( 0, 0 );
if ( $qualifier eq 'ON' ) {
return $s->elem( 0, 1 );
}
}
}
return;
}
sub lineitems {
my $self = shift;
if ( $self->{quotation_lines} ) {
@ -280,6 +296,10 @@ Missing POD for buyer_ean.
Missing POD for supplier_ean.
=head2 purchase_order_number
Missing POD for purchase_order_number.
=head2 lineitems
Missing POD for lineitems.

View File

@ -93,6 +93,7 @@ if ( $op eq 'acct_form' ) {
auto_orders => $input->param('auto_orders') ? 1 : 0,
id_code_qualifier => scalar $input->param('id_code_qualifier'),
plugin => scalar $input->param('plugin'),
po_is_basketname => $input->param('po_is_basketname') ? 1 : 0,
};
if ($id) {

View File

@ -96,9 +96,10 @@
<span>New account</span>
[% END %]
</h1>
<fieldset class="rows">
<legend class="sr-only">Account details</legend>
<!-- Basic Information -->
<fieldset class="rows">
<legend>Basic Information</legend>
<ol>
<li>
<label for="vendor_id">Vendor: </label>
@ -112,6 +113,10 @@
[% END %]
</select>
</li>
<li>
<label for="description">Description: </label>
<input type="text" name="description" id="description" size="20" value="[% account.description | html %]" />
</li>
[% IF plugins %]
<li>
<label for="plugin">Plugin: </label>
@ -129,24 +134,6 @@
[% ELSE %]
<input type="hidden" name="plugin" value="" />
[% END %]
<li>
<label for="description">Description: </label>
<input type="text" name="description" id="description" size="20" value="[% account.description | html %]" />
</li>
<li>
<label for="file_transport_id">File transport: </label>
<select name="file_transport_id" id="file_transport_id">
<option value="">Select a file transport configuration</option>
[% FOREACH transport IN file_transports %]
[% IF transport.file_transport_id == account.file_transport_id %]
<option value="[% transport.file_transport_id | html %]" selected="selected">[% transport.name | html %] ([% transport.transport | upper | html %] - [% transport.host | html %])</option>
[% ELSE %]
<option value="[% transport.file_transport_id | html %]">[% transport.name | html %] ([% transport.transport | upper | html %] - [% transport.host | html %])</option>
[% END %]
[% END %]
</select>
<div class="hint"> Select a file transport configuration for this EDI account. File transports can be managed in <a href="/cgi-bin/koha/admin/file_transports.pl">Administration &rsaquo; File transports</a>. </div>
</li>
<li>
<label for="id_code_qualifier">Qualifier:</label>
<select name="id_code_qualifier" id="id_code_qualifier">
@ -180,6 +167,34 @@
[% END %]
</select>
</li>
</ol>
</fieldset>
<!-- Transport Settings -->
<fieldset class="rows">
<legend>Transport Settings</legend>
<ol>
<li>
<label for="file_transport_id">File transport: </label>
<select name="file_transport_id" id="file_transport_id">
<option value="">Select a file transport configuration</option>
[% FOREACH transport IN file_transports %]
[% IF transport.file_transport_id == account.file_transport_id %]
<option value="[% transport.file_transport_id | html %]" selected="selected">[% transport.name | html %] ([% transport.transport | upper | html %] - [% transport.host | html %])</option>
[% ELSE %]
<option value="[% transport.file_transport_id | html %]">[% transport.name | html %] ([% transport.transport | upper | html %] - [% transport.host | html %])</option>
[% END %]
[% END %]
</select>
<div class="hint"> Select a file transport configuration for this EDI account. File transports can be managed in <a href="/cgi-bin/koha/admin/file_transports.pl">Administration &rsaquo; File transports</a>. </div>
</li>
</ol>
</fieldset>
<!-- Message Types -->
<fieldset class="rows">
<legend>Message Types</legend>
<ol>
<li>
<label for="quotes_enabled">Quotes enabled: </label>
[% IF account.quotes_enabled %]
@ -212,6 +227,13 @@
<input type="checkbox" name="responses_enabled" id="responses_enabled" value="1" />
[% END %]
</li>
</ol>
</fieldset>
<!-- Functional Switches -->
<fieldset class="rows">
<legend>Functional Switches</legend>
<ol>
<li>
<label for="auto_orders">Automatic ordering: </label>
[% IF account.auto_orders %]
@ -221,6 +243,18 @@
[% END %]
<div class="hint"> With automatic ordering quotes generate orders without staff intervention. </div>
</li>
<li>
<label for="po_is_basketname">Use purchase order numbers: </label>
[% IF account.po_is_basketname %]
<input type="checkbox" name="po_is_basketname" id="po_is_basketname" value="1" checked="checked" />
[% ELSE %]
<input type="checkbox" name="po_is_basketname" id="po_is_basketname" value="1" />
[% END %]
<div class="hint">
When enabled, basket names are used as purchase order numbers. <br />For received QUOTE messages, we will use the RFF+ON field to populate the basket name. <br />For generated ORDER messages, we will use the
basket name to populate the BGM segment.</div
>
</li>
</ol>
</fieldset>