Bugzilla – Attachment 186460 Details for
Bug 40808
Consider a link table for accountlines to varying other Koha tables
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40808: Add Koha::Object classes for accountline_links and update existing objects
Bug-40808-Add-KohaObject-classes-for-accountlineli.patch (text/plain), 13.11 KB, created by
Martin Renvoize (ashimema)
on 2025-09-16 09:15:18 UTC
(
hide
)
Description:
Bug 40808: Add Koha::Object classes for accountline_links and update existing objects
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-09-16 09:15:18 UTC
Size:
13.11 KB
patch
obsolete
>From 4cf48ac6937331284390bb846bc41a733ad38458 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Mon, 15 Sep 2025 12:17:32 +0100 >Subject: [PATCH] Bug 40808: Add Koha::Object classes for accountline_links and > update existing objects > >This patch implements the Koha::Object layer for the new polymorphic >account line linking system. > >New classes: >- Koha::Account::Link - Individual link object with validation >- Koha::Account::Links - Collection class with filtering methods > >Enhanced existing classes: >- Koha::Account::Line gains methods: add_link, links, holds >- Koha::Hold gains method: account_lines > >Features: >- Clean API using modern class names (holds) >- Built-in validation for link integrity >- Optimized queries with proper joins and prefetch >- Seamless integration with existing Koha::Object patterns > >Usage examples: > my $fees = $hold->debits; > my $holds = $account_line->holds; > $account_line->add_link('hold', $hold_id); >--- > Koha/Account/Line.pm | 62 +++++++++++++ > Koha/Account/Link.pm | 183 +++++++++++++++++++++++++++++++++++++ > Koha/Account/Links.pm | 125 +++++++++++++++++++++++++ > Koha/Exceptions/Account.pm | 16 ++++ > Koha/Hold.pm | 18 ++++ > 5 files changed, 404 insertions(+) > create mode 100644 Koha/Account/Link.pm > create mode 100644 Koha/Account/Links.pm > >diff --git a/Koha/Account/Line.pm b/Koha/Account/Line.pm >index c796b92275a..77388ad4097 100644 >--- a/Koha/Account/Line.pm >+++ b/Koha/Account/Line.pm >@@ -23,6 +23,8 @@ use C4::Log qw( logaction ); > > use Koha::Account::CreditType; > use Koha::Account::DebitType; >+use Koha::Account::Link; >+use Koha::Account::Links; > use Koha::Account::Offsets; > use Koha::Database; > use Koha::DateUtils qw( dt_from_string ); >@@ -1100,6 +1102,66 @@ sub store { > return $self->SUPER::store(); > } > >+=head3 add_link >+ >+Add a link to another entity (hold, checkout, article request, etc.) >+ >+ $account_line->add_link('hold', $hold_id); >+ >+=cut >+ >+sub add_link { >+ my ( $self, $link_type, $linked_id ) = @_; >+ >+ return Koha::Account::Link->new( >+ { >+ accountlines_id => $self->id, >+ link_type => $link_type, >+ linked_id => $linked_id, >+ } >+ )->store; >+} >+ >+=head3 links >+ >+Get all links for this account line >+ >+ my $links = $account_line->links; >+ >+=cut >+ >+sub links { >+ my ($self) = @_; >+ >+ my $links_rs = $self->_result->search_related('accountline_links'); >+ return Koha::Account::Links->_new_from_dbic($links_rs); >+} >+ >+=head3 holds >+ >+Get all holds linked to this account line >+ >+ my @holds = $account_line->holds; >+ >+=cut >+ >+sub holds { >+ my ($self) = @_; >+ >+ # Get all hold IDs - we only use 'hold' link_type for both current and old holds >+ my @hold_ids = $self->links->search( { link_type => 'hold' } )->get_column('linked_id'); >+ >+ return () unless @hold_ids; >+ >+ # Search both current holds and old holds with the same IDs >+ # The reserve_id is the same in both tables >+ my @holds = Koha::Holds->search( { reserve_id => { -in => \@hold_ids } } )->as_list; >+ >+ my @old_holds = Koha::Old::Holds->search( { reserve_id => { -in => \@hold_ids } } )->as_list; >+ >+ return ( @holds, @old_holds ); >+} >+ > =head2 Internal methods > > =cut >diff --git a/Koha/Account/Link.pm b/Koha/Account/Link.pm >new file mode 100644 >index 00000000000..bd8dbf7e103 >--- /dev/null >+++ b/Koha/Account/Link.pm >@@ -0,0 +1,183 @@ >+package Koha::Account::Link; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Carp qw( croak ); >+use Koha::Exceptions::Account; >+ >+use base qw(Koha::Object); >+ >+=head1 NAME >+ >+Koha::Account::Link - Koha Account Link Object class >+ >+=head1 API >+ >+=head2 Class methods >+ >+=head3 store >+ >+Validates the link before storing >+ >+=cut >+ >+sub store { >+ my ($self) = @_; >+ >+ my $link_type = $self->link_type; >+ my $linked_id = $self->linked_id; >+ >+ # Check for valid link type first >+ my $validators = { >+ 'hold' => sub { Koha::Holds->find( $_[0] ) || Koha::Old::Holds->find( $_[0] ) }, >+ }; >+ >+ unless ( exists $validators->{$link_type} ) { >+ Koha::Exceptions::Account::InvalidLinkType->throw("Unknown link_type: $link_type"); >+ } >+ >+ # Validate the linked entity exists >+ unless ( $self->_validate_link_integrity() ) { >+ Koha::Exceptions::Account::InvalidLinkTarget->throw( >+ "Invalid link target: " . $link_type . " with ID " . $linked_id . " does not exist" ); >+ } >+ >+ return $self->SUPER::store(); >+} >+ >+=head3 linked_object >+ >+Returns the linked object based on link_type and linked_id >+ >+=cut >+ >+sub linked_object { >+ my ($self) = @_; >+ >+ return $self->_result->linked_object; >+} >+ >+=head3 linked_koha_object >+ >+Returns the Koha::Object representation of the linked object >+ >+=cut >+ >+sub linked_koha_object { >+ my ($self) = @_; >+ >+ # Special handling for holds - they can return either Koha::Hold or Koha::Old::Hold >+ if ( $self->link_type eq 'hold' ) { >+ my $dbic_object = $self->linked_object; >+ return unless $dbic_object; >+ >+ # Check which table the result came from by examining the result source >+ my $source_name = $dbic_object->result_source->source_name; >+ >+ if ( $source_name eq 'Reserve' ) { >+ require Koha::Hold; >+ return Koha::Hold->_new_from_dbic($dbic_object); >+ } elsif ( $source_name eq 'OldReserve' ) { >+ require Koha::Old::Hold; >+ return Koha::Old::Hold->_new_from_dbic($dbic_object); >+ } >+ >+ return; # Unknown source >+ } >+ >+ # Handle other link types normally >+ my $class_map = { >+ 'checkout' => 'Koha::Checkout', >+ 'old_checkout' => 'Koha::Old::Checkout', >+ 'article_request' => 'Koha::ArticleRequest', >+ }; >+ >+ my $class = $class_map->{ $self->link_type }; >+ return unless $class; >+ >+ # Load the class if needed >+ eval "require $class"; >+ if ($@) { >+ Koha::Exceptions::Account::InvalidLinkType->throw( >+ "Could not load class $class for link_type '" . $self->link_type . "': $@" ); >+ } >+ >+ return $class->_new_from_dbic( $self->linked_object ); >+} >+ >+=head3 _validate_link_integrity >+ >+Internal method to validate that the linked entity exists >+ >+=cut >+ >+sub _validate_link_integrity { >+ my ($self) = @_; >+ >+ my $link_type = $self->link_type; >+ my $linked_id = $self->linked_id; >+ >+ # Define valid link types and their validation methods >+ my $validators = { >+ 'hold' => sub { Koha::Holds->find( $_[0] ) || Koha::Old::Holds->find( $_[0] ) }, >+ }; >+ >+ my $validator = $validators->{$link_type}; >+ return 0 unless $validator; # Invalid link type >+ >+ return $validator->($linked_id) ? 1 : 0; >+} >+ >+=head2 Class Methods >+ >+=head3 _type >+ >+=cut >+ >+sub _type { >+ return 'AccountlineLink'; >+} >+ >+=head1 AUTHOR >+ >+Koha Development Team <http://koha-community.org/> >+ >+=head1 COPYRIGHT >+ >+Copyright 2025 Koha Development Team >+ >+=head1 LICENSE >+ >+This file is part of Koha. >+ >+Koha is free software; you can redistribute it and/or modify it >+under the terms of the GNU General Public License as published by >+the Free Software Foundation; either version 3 of the License, or >+(at your option) any later version. >+ >+Koha is distributed in the hope that it will be useful, but >+WITHOUT ANY WARRANTY; without even the implied warranty of >+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+GNU General Public License for more details. >+ >+You should have received a copy of the GNU General Public License >+along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+=cut >+ >+1; >diff --git a/Koha/Account/Links.pm b/Koha/Account/Links.pm >new file mode 100644 >index 00000000000..0c470243ee2 >--- /dev/null >+++ b/Koha/Account/Links.pm >@@ -0,0 +1,125 @@ >+package Koha::Account::Links; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use base qw(Koha::Objects); >+ >+=head1 NAME >+ >+Koha::Account::Links - Koha Account Links Object set class >+ >+=head1 API >+ >+=head2 Class methods >+ >+=head3 by_link_type >+ >+Filter links by link_type >+ >+ my $reserve_links = $links->by_link_type('reserve'); >+ >+=cut >+ >+sub by_link_type { >+ my ( $self, $link_type ) = @_; >+ >+ return $self->search( { link_type => $link_type } ); >+} >+ >+=head3 by_linked_id >+ >+Filter links by linked_id >+ >+ my $links = $links->by_linked_id(12345); >+ >+=cut >+ >+sub by_linked_id { >+ my ( $self, $linked_id ) = @_; >+ >+ return $self->search( { linked_id => $linked_id } ); >+} >+ >+=head3 holds >+ >+Get all holds linked to these account lines >+ >+=cut >+ >+sub holds { >+ my ($self) = @_; >+ >+ # Get all hold IDs - we only use 'hold' link_type for both current and old holds >+ my @hold_ids = $self->search( { link_type => 'hold' } )->get_column('linked_id'); >+ >+ return () unless @hold_ids; >+ >+ # Search both current holds and old holds with the same IDs >+ # The reserve_id is the same in both tables >+ my @holds = Koha::Holds->search( { reserve_id => { -in => \@hold_ids } } )->as_list; >+ my @old_holds = Koha::Old::Holds->search( { reserve_id => { -in => \@hold_ids } } )->as_list; >+ >+ return ( @holds, @old_holds ); >+} >+ >+=head2 Class Methods >+ >+=head3 _type >+ >+=cut >+ >+sub _type { >+ return 'AccountlineLink'; >+} >+ >+=head3 object_class >+ >+=cut >+ >+sub object_class { >+ return 'Koha::Account::Link'; >+} >+ >+=head1 AUTHOR >+ >+Koha Development Team <http://koha-community.org/> >+ >+=head1 COPYRIGHT >+ >+Copyright 2025 Koha Development Team >+ >+=head1 LICENSE >+ >+This file is part of Koha. >+ >+Koha is free software; you can redistribute it and/or modify it >+under the terms of the GNU General Public License as published by >+the Free Software Foundation; either version 3 of the License, or >+(at your option) any later version. >+ >+Koha is distributed in the hope that it will be useful, but >+WITHOUT ANY WARRANTY; without even the implied warranty of >+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+GNU General Public License for more details. >+ >+You should have received a copy of the GNU General Public License >+along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+=cut >+ >+1; >diff --git a/Koha/Exceptions/Account.pm b/Koha/Exceptions/Account.pm >index 0b36f0818f9..16354c6b0e3 100644 >--- a/Koha/Exceptions/Account.pm >+++ b/Koha/Exceptions/Account.pm >@@ -55,6 +55,14 @@ use Exception::Class ( > 'Koha::Exceptions::Account::InvalidPaymentType' => { > isa => 'Koha::Exceptions::Account', > description => 'Invalid payment type' >+ }, >+ 'Koha::Exceptions::Account::InvalidLinkType' => { >+ isa => 'Koha::Exceptions::Account', >+ description => 'Invalid account line link type' >+ }, >+ 'Koha::Exceptions::Account::InvalidLinkTarget' => { >+ isa => 'Koha::Exceptions::Account', >+ description => 'Invalid account line link target' > } > ); > >@@ -98,6 +106,14 @@ Exception to be used when a passed credit or debit is not of a recognised type. > > Exception to be used when UseCashRegisters is enabled and one is not passed for a transaction. > >+=head2 Koha::Exceptions::Account::InvalidLinkType >+ >+Exception to be used when an invalid link type is provided to account line linking. >+ >+=head2 Koha::Exceptions::Account::InvalidLinkTarget >+ >+Exception to be used when an account line link target does not exist or is invalid. >+ > =cut > > 1; >diff --git a/Koha/Hold.pm b/Koha/Hold.pm >index 801d052fe82..f644475473c 100644 >--- a/Koha/Hold.pm >+++ b/Koha/Hold.pm >@@ -1227,6 +1227,9 @@ sub charge_hold_fee { > } > ); > >+ # Link the account line to this hold >+ $line->add_link( 'hold', $self->id ); >+ > return $line; > } > >@@ -1450,6 +1453,21 @@ sub strings_map { > return $strings; > } > >+=head3 debits >+ >+ my $fees = $hold->debits; >+ >+Get all debit account lines (charges) associated with this hold >+ >+=cut >+ >+sub debits { >+ my ($self) = @_; >+ >+ my $accountlines_rs = $self->_result->search_related('accountline_links')->search_related('accountline'); >+ return Koha::Account::Debits->_new_from_dbic($accountlines_rs); >+} >+ > =head2 Internal methods > > =head3 _type >-- >2.51.0
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 40808
:
186436
|
186437
|
186438
|
186439
|
186440
|
186441
|
186442
|
186443
|
186458
|
186459
| 186460 |
186461
|
186462
|
186463
|
186464
|
186465