From 29b16b18c18245692aea34dc741425b063cd8ff1 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 11 Jul 2025 13:47:33 +0100 Subject: [PATCH] Bug 20253: (follow-up) Add duplicate purchase order number validation When processing EDI quotes with purchase order numbers, validate that the purchase order number is unique for the vendor to prevent operational confusion. The validation: - Checks for existing baskets with the same purchase order number and vendor - Includes both open and closed baskets in the uniqueness check - Logs an error with the raw RFF+ON segment and details to the edifact_errors table - Continues processing (non-blocking) to prevent data loss - Provides system log warnings for monitoring The error logging includes: - Section: Raw RFF+ON segment (e.g., "RFF+ON:orders 23/1") - Details: Clear description of the duplicate purchase order number issue This ensures administrators can identify and resolve duplicate purchase order numbers while maintaining system functionality and audit trails. --- Koha/EDI.pm | 26 ++++++++++++++++ t/db_dependent/Koha/EDI.t | 63 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/Koha/EDI.pm b/Koha/EDI.pm index ce349b501db..06561614680 100644 --- a/Koha/EDI.pm +++ b/Koha/EDI.pm @@ -663,6 +663,32 @@ sub process_quote { my $purchase_order_number = $msg->purchase_order_number; if ($purchase_order_number) { $basket_name = $purchase_order_number; + + # Check for duplicate purchase order numbers for this vendor (including closed baskets) + my $existing_basket = $schema->resultset('Aqbasket')->search( + { + basketname => $basket_name, + booksellerid => $quote_message->vendor_id, + } + )->first; + + if ($existing_basket) { + + # Log error for duplicate purchase order number but continue processing + my $rff_segment = "RFF+ON:$purchase_order_number"; + $quote_message->add_to_edifact_errors( + { + section => $rff_segment, + details => "Duplicate purchase order number '$purchase_order_number' found for vendor " + . $quote_message->vendor_id . "." + } + ); + $logger->warn( "Duplicate purchase order number '$purchase_order_number' for vendor " + . $quote_message->vendor_id + . " (existing basket: " + . $existing_basket->basketno + . ")" ); + } } } diff --git a/t/db_dependent/Koha/EDI.t b/t/db_dependent/Koha/EDI.t index 3182930939d..550ff7a5ad7 100755 --- a/t/db_dependent/Koha/EDI.t +++ b/t/db_dependent/Koha/EDI.t @@ -38,7 +38,7 @@ my $builder = t::lib::TestBuilder->new; my $logger = t::lib::Mocks::Logger->new(); subtest 'process_quote' => sub { - plan tests => 6; + plan tests => 7; $schema->storage->txn_begin; @@ -740,6 +740,67 @@ subtest 'process_quote' => sub { $schema->storage->txn_rollback; }; + # Test 7: Duplicate purchase order number validation + subtest 'duplicate_purchase_order_validation' => sub { + plan tests => 5; + + $schema->storage->txn_begin; + + # Create vendor EDI account with po_is_basketname set to true + my $account = $builder->build( + { + source => 'VendorEdiAccount', + value => { + description => 'test vendor duplicate po', + transport => 'FILE', + po_is_basketname => 1, + }, + } + ); + + # Create first basket with purchase order number "orders 23/1" (same as in QUOTES_SMALL.CEQ) + my $first_basket = $builder->build( + { + source => 'Aqbasket', + value => { + basketname => 'orders 23/1', + booksellerid => $account->{vendor_id}, + closedate => undef, # Open basket + }, + } + ); + + # Use existing test file that contains RFF+ON:orders 23/1 + my $filename = 'QUOTES_SMALL.CEQ'; + my $trans = Koha::Edifact::Transport->new( $account->{id} ); + $trans->working_directory($dirname); + + my $mhash = $trans->message_hash(); + $mhash->{message_type} = 'QUOTE'; + $trans->ingest( $mhash, $filename ); + + my $quote = $schema->resultset('EdifactMessage')->find( { filename => $filename } ); + ok( $quote, 'Quote message created successfully' ); + + # Process the quote (this should trigger duplicate detection) + process_quote($quote); + + # Check that duplicate purchase order error was logged + my $errors = $quote->edifact_errors; + ok( $errors->count >= 1, 'At least one error logged during quote processing' ); + + # Find the specific duplicate purchase order error + my $duplicate_error = $errors->search( { section => 'RFF+ON:orders 23/1' } )->first; + ok( $duplicate_error, 'Duplicate purchase order error found' ); + is( $duplicate_error->section, 'RFF+ON:orders 23/1', 'Error section contains the RFF+ON segment' ); + like( + $duplicate_error->details, qr/Duplicate purchase order number 'orders 23\/1' found for vendor/, + 'Error details describe the duplicate issue' + ); + + $schema->storage->txn_rollback; + }; + # Clean up $logger->clear(); $schema->storage->txn_rollback; -- 2.50.0