Bug 20253: (follow-up) Make basket name read-only when derived from EDI purchase order number

When a basket is created from an EDI quote with the vendor EDI account configured
to use purchase order numbers, the basket name should be protected from changes
to maintain the integrity of the purchase order number reference.

This patch:
- Makes the basket name field read-only in the UI when the basket was created
  from EDI with purchase order number setting
- Adds explanatory text when the field is protected
- Implements server-side protection to prevent basket name changes even if
  the UI is bypassed
- Preserves the original purchase order number derived name

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-11 12:31:34 +01:00 committed by Lucas Gass
parent 458608b9c4
commit 1e2e89e43f
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
3 changed files with 78 additions and 3 deletions

View File

@ -135,6 +135,30 @@ sub edi_order {
return $order_rs->single;
}
=head3 edi_quote
my $edi_order = $basket->edi_quote;
Returns the EDI quote object if one was used to generate this basket.
NOTE: This currently returns a bare DBIx::Class result or undefined. This is consistent with the rest of EDI;
However it would be beneficial to convert these to full fledge Koha::Objects in the future.
=cut
sub edi_quote {
my ($self) = @_;
my $order_rs = $self->_result->edifact_messages(
{
message_type => 'QUOTE',
deleted => 0
},
{ order_by => { '-desc' => 'transfer_date' }, rows => 1 }
);
return $order_rs->single;
}
=head3 effective_create_items
Returns C<create_items> for this basket, falling back to C<AcqCreateItem> if unset.

View File

@ -56,6 +56,7 @@ use C4::Contract qw( GetContracts GetContract );
use Koha::Acquisition::Booksellers;
use Koha::Acquisition::Baskets;
use Koha::AdditionalFields;
use Koha::Database;
my $input = CGI->new;
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
@ -122,6 +123,24 @@ if ( $op eq 'add_form' ) {
);
}
# Check if basket name should be read-only (EDI-generated with PO number setting)
my $basket_name_readonly = 0;
if ( $basketno && $basket ) {
my $basket_obj = Koha::Acquisition::Baskets->find($basketno);
if ($basket_obj) {
my $edi_quote = $basket_obj->edi_quote;
if ($edi_quote) {
# This basket was created from an EDI quote
# Check if the vendor EDI account is configured to use purchase order numbers
my $vendor_edi_account = $edi_quote->edi_acct;
if ( $vendor_edi_account && $vendor_edi_account->po_is_basketname ) {
$basket_name_readonly = 1;
}
}
}
}
$template->param(
add_form => 1,
basketname => $basket->{'basketname'},
@ -132,6 +151,7 @@ if ( $op eq 'add_form' ) {
basketno => $basketno,
is_standing => $basket->{is_standing},
create_items => $basket->{create_items},
basket_name_readonly => $basket_name_readonly,
);
my $billingplace = $basket->{'billingplace'} || C4::Context->userenv->{"branch"};
@ -145,9 +165,34 @@ if ( $op eq 'add_form' ) {
#we are confirming the changes, save the basket
if ($is_an_edit) {
# Check if basket name should be protected from changes
my $basket_name = scalar $input->param('basketname');
my $current_basket = GetBasket($basketno);
# If this basket was created from EDI with PO number setting, prevent name changes
my $basket_obj = Koha::Acquisition::Baskets->find($basketno);
if ($basket_obj) {
my $edi_order = $basket_obj->edi_order;
if ($edi_order) {
# This basket was created from an EDI order/quote
# Check if the vendor EDI account is configured to use purchase order numbers
my $schema = Koha::Database->new()->schema();
my $vendor_edi_account = $schema->resultset('VendorEdiAccount')
->search( { vendor_id => scalar $input->param('basketbooksellerid') } )->first;
if ( $vendor_edi_account && $vendor_edi_account->po_is_basketname ) {
# Preserve the original basket name
$basket_name = $current_basket->{'basketname'};
}
}
}
ModBasketHeader(
$basketno,
scalar $input->param('basketname'),
$basket_name,
scalar $input->param('basketnote'),
scalar $input->param('basketbooksellernote'),
scalar $input->param('basketcontractnumber') || undef,

View File

@ -68,8 +68,14 @@
[% END %]
<li>
<label for="basketname" class="required">Basket name: </label>
<input type="text" name="basketname" id="basketname" size="40" maxlength="80" value="[% basketname | html %]" required="required" class="focus required" />
<span class="required">Required</span>
[% IF basket_name_readonly %]
<input type="text" name="basketname" id="basketname" size="40" maxlength="80" value="[% basketname | html %]" required="required" class="focus required" readonly="readonly" />
<span class="required">Required</span>
<div class="hint">This basket name is derived from the purchase order number and cannot be changed.</div>
[% ELSE %]
<input type="text" name="basketname" id="basketname" size="40" maxlength="80" value="[% basketname | html %]" required="required" class="focus required" />
<span class="required">Required</span>
[% END %]
</li>
<li>
<label for="billingplace">Billing place: </label>