if ( $rentalConfirmation ){
my ($rentalCharge) = GetIssuingCharges( $item->itemnumber, $patron->borrowernumber );
+ my $itemtype = Koha::ItemTypes->find( $item->itype ); # GetItem sets effective itemtype
+ $rentalCharge += $itemtype->calc_rental_charge_daily( { from => dt_from_string(), to => $duedate } );
if ( $rentalCharge > 0 ){
$needsconfirmation{RENTALCHARGE} = $rentalCharge;
}
AddIssuingCharge( $issue, $charge, $description );
}
+ my $itemtype = Koha::ItemTypes->find( $item_object->effective_itemtype );
+ if ( $itemtype ) {
+ my $daily_charge = $itemtype->calc_rental_charge_daily( { from => $issuedate, to => $datedue } );
+ if ( $daily_charge > 0 ) {
+ AddIssuingCharge( $issue, $daily_charge, 'Daily rental' ) if $daily_charge > 0;
+ $charge += $daily_charge;
+ $item->{charge} = $charge;
+ }
+ }
+
# Record the fact that this book was issued.
&UpdateStats(
{
$renews = $item->renewals + 1;
ModItem( { renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $item->biblionumber, $itemnumber, { log_action => 0 } );
- # Charge a new rental fee, if applicable?
+ # Charge a new rental fee, if applicable
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
if ( $charge > 0 ) {
my $description = "Renewal of Rental Item " . $biblio->title . " " .$item->barcode;
AddIssuingCharge($issue, $charge, $description);
}
+ # Charge a new daily rental fee, if applicable
+ my $itemtype = Koha::ItemTypes->find( $item_object->effective_itemtype );
+ if ( $itemtype ) {
+ my $daily_charge = $itemtype->calc_rental_charge_daily( { from => dt_from_string($lastreneweddate), to => $datedue } );
+ if ( $daily_charge > 0 ) {
+ my $type_desc = "Renewal of Daily Rental Item " . $biblio->title . " $item->{'barcode'}";
+ AddIssuingCharge( $issue, $daily_charge, $type_desc )
+ }
+ $charge += $daily_charge;
+ }
+
# Send a renewal slip according to checkout alert preferencei
if ( C4::Context->preference('RenewalSendNotice') eq '1' ) {
my $circulation_alert = 'C4::ItemCirculationAlertPreference';
=head2 AddIssuingCharge
- &AddIssuingCharge( $checkout, $charge )
+ &AddIssuingCharge( $checkout, $charge, [$description] )
=cut
} @translated_descriptions ];
}
+=head3 calc_rental_charge_daily
+
+ my $fee = $itemtype->calc_rental_charge_daily( { from => $dt_from, to => $dt_to } );
+
+ This method calculates the daily rental fee for a given itemtype for a given
+ period of time passed in as a pair of DateTime objects.
+
+=cut
+
+sub calc_rental_charge_daily {
+ my ( $self, $params ) = @_;
+
+ my $rental_charge_daily = $self->rental_charge_daily;
+ return 0 unless $rental_charge_daily;
+
+ my $from_dt = $params->{from};
+ my $to_dt = $params->{to};
+
+ my $duration;
+ if ( C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed' ) {
+ my $branchcode = C4::Context->userenv->{branch};
+ my $calendar = Koha::Calendar->new( branchcode => $branchcode );
+ $duration = $calendar->days_between( $from_dt, $to_dt );
+ }
+ else {
+ $duration = $to_dt->delta_days($from_dt);
+ }
+ my $days = $duration->in_units('days');
+
+ my $charge = $rental_charge_daily * $days;
+
+ return $charge;
+}
=head3 can_be_deleted
my $itemtype = Koha::ItemTypes->find($itemtype_code);
my $description = $input->param('description');
my $rentalcharge = $input->param('rentalcharge');
+ my $rental_charge_daily = $input->param('rental_charge_daily');
my $defaultreplacecost = $input->param('defaultreplacecost');
my $processfee = $input->param('processfee');
my $image = $input->param('image') || q||;
if ( $itemtype and $is_a_modif ) { # it's a modification
$itemtype->description($description);
$itemtype->rentalcharge($rentalcharge);
+ $itemtype->rental_charge_daily($rental_charge_daily);
$itemtype->defaultreplacecost($defaultreplacecost);
$itemtype->processfee($processfee);
$itemtype->notforloan($notforloan);
}
} elsif ( not $itemtype and not $is_a_modif ) {
my $itemtype = Koha::ItemType->new(
- { itemtype => $itemtype_code,
- description => $description,
- rentalcharge => $rentalcharge,
- defaultreplacecost => $defaultreplacecost,
- processfee => $processfee,
- notforloan => $notforloan,
- imageurl => $imageurl,
- summary => $summary,
- checkinmsg => $checkinmsg,
- checkinmsgtype => $checkinmsgtype,
- sip_media_type => $sip_media_type,
- hideinopac => $hideinopac,
- searchcategory => $searchcategory,
+ {
+ itemtype => $itemtype_code,
+ description => $description,
+ rentalcharge => $rentalcharge,
+ rental_charge_daily => $rental_charge_daily,
+ defaultreplacecost => $defaultreplacecost,
+ processfee => $processfee,
+ notforloan => $notforloan,
+ imageurl => $imageurl,
+ summary => $summary,
+ checkinmsg => $checkinmsg,
+ checkinmsgtype => $checkinmsgtype,
+ sip_media_type => $sip_media_type,
+ hideinopac => $hideinopac,
+ searchcategory => $searchcategory,
}
);
eval { $itemtype->store; };
$data->{'itemtypename'} = $itemtypes->{ $data->{'itemtype'} }->{'translated_description'}
if $data->{itemtype} && exists $itemtypes->{ $data->{itemtype} };
-$data->{'rentalcharge'} = $data->{'rentalcharge'};
foreach ( keys %{$data} ) {
$template->param( "$_" => defined $data->{$_} ? $data->{$_} : '' );
}
[% END %]
[% END %]
</select>
- (Options are defined as the authorized values for the ITEMTYPECAT category)
+ <span class="hint">Options are defined as the authorized values for the ITEMTYPECAT category.</span>
</li>
[% IF Koha.Preference('noItemTypeImages') %]
<li>
[% ELSE %]
<input type="checkbox" id="hideinopac" name="hideinopac" value="1" />
[% END %]
- (if checked, items of this type will be hidden as filters in OPAC's advanced search)
+ <span class="hint">If checked, items of this type will be hidden as filters in OPAC's advanced search.</span>
</li>
<li>
<label for="notforloan">Not for loan: </label>
[% ELSE %]
<input type="checkbox" id="notforloan" name="notforloan" value="1" />
[% END %]
- (if checked, no item of this type can be issued. If not checked, every item of this type can be issued unless notforloan is set for a specific item)
+ <span class="hint">If checked, no item of this type can be issued. If not checked, every item of this type can be issued unless notforloan is set for a specific item.</span>
</li>
<li>
<label for="rentalcharge">Rental charge: </label>
- <input type="text" id="rentalcharge" name="rentalcharge" size="10" value="[% itemtype.rentalcharge | html %]" />
+ <input type="text" id="rentalcharge" name="rentalcharge" size="10" value="[% itemtype.rentalcharge | $Price %]" />
+ <span class="hint">This fee is charged once per checkout/renewal per item</span>
+ </li>
+ <li>
+ <label for="rental_charge_daily">Daily rental charge: </label>
+ <input type="text" id="rental_charge_daily" name="rental_charge_daily" size="10" value="[% itemtype.rental_charge_daily | $Price %]" />
+ <span class="hint">This fee is charged a checkout/renewal time for each day between the checkout/renewal date and due date.</span>
</li>
<li>
<label for="defaultreplacecost">Default replacement cost: </label>
<th>Search category</th>
<th>Not for loan</th>
<th>Hide in OPAC</th>
- <th>Charge</th>
+ <th>Rental charge</th>
+ <th>Daily rental charge</th>
<th>Default replacement cost</th>
<th>Processing fee (when lost)</th>
<th>Checkin message</th>
[% itemtype.rentalcharge | $Price %]
[% END %]
</td>
+ <td>
+ [% UNLESS ( itemtype.notforloan ) %]
+ [% itemtype.rental_charge_daily | $Price %]
+ [% END %]
+ </td>
<td>[% itemtype.defaultreplacecost | $Price %]</td>
<td>[% itemtype.processfee | $Price %]</td>
<td>[% itemtype.checkinmsg | html_line_break | $raw %]</td>
[% USE raw %]
+[% USE Price %]
[% USE Asset %]
[% USE Koha %]
[% USE Branches %]
<li><span class="label">Item type:</span> [% itemtypename | html %] </li>
[% END %]
[% IF ( rentalcharge ) %]<li><span class="label">Rental charge:</span>[% rentalcharge | $Price %] </li>[% END %]
+ [% IF ( rental_charge_daily ) %]<li><span class="label">Daily rental charge:</span>[% rental_charge_daily | $Price %] </li>[% END %]
<li><span class="label">ISBN:</span> [% isbn | html %] </li>
<li><span class="label">Publisher:</span>[% place | html %] [% publishercode | html %] [% publicationyear | html %] </li>
[% IF ( volumeddesc ) %]<li><span class="label">Volume:</span> [% volumeddesc | html %]</li>[% END %]
source => 'Branch',
});
my $itemtype = $builder->build(
- { source => 'Itemtype',
- value => { notforloan => undef, rentalcharge => 0, defaultreplacecost => undef, processfee => undef }
+ {
+ source => 'Itemtype',
+ value => {
+ notforloan => undef,
+ rentalcharge => 0,
+ rental_charge_daily => 0,
+ defaultreplacecost => undef,
+ processfee => undef
+ }
}
)->{itemtype};
my $patron_category = $builder->build(
$expected_expiration_date, 'Test at line ' . $line_number );
Koha::Patron::Debarments::DelUniqueDebarment(
{ borrowernumber => $patron->{borrowernumber}, type => 'SUSPENSION' } );
-}
+};
+
+subtest 'Koha::ItemType::calc_rental_charge_daily tests' => sub {
+ plan tests => 8;
+
+ t::lib::Mocks::mock_preference('item-level_itypes', 1);
+
+ my $library = $builder->build_object( { class => 'Koha::Libraries' } )->store;
+
+ my $module = new Test::MockModule('C4::Context');
+ $module->mock('userenv', sub { { branch => $library->id } });
+
+ my $patron = $builder->build_object(
+ {
+ class => 'Koha::Patrons',
+ value => { categorycode => $patron_category->{categorycode} }
+ }
+ )->store;
+
+ my $itemtype = $builder->build_object(
+ {
+ class => 'Koha::ItemTypes',
+ value => {
+ notforloan => undef,
+ rentalcharge => 0,
+ rental_charge_daily => 1.000000
+ }
+ }
+ )->store;
+
+ my $biblioitem = $builder->build( { source => 'Biblioitem' } );
+ my $item = $builder->build_object(
+ {
+ class => 'Koha::Items',
+ value => {
+ homebranch => $library->id,
+ holdingbranch => $library->id,
+ notforloan => 0,
+ itemlost => 0,
+ withdrawn => 0,
+ itype => $itemtype->id,
+ biblionumber => $biblioitem->{biblionumber},
+ biblioitemnumber => $biblioitem->{biblioitemnumber},
+ }
+ }
+ )->store;
+
+ is( $itemtype->rental_charge_daily, '1.000000', 'Daily rental charge stored and retreived correctly' );
+ is( $item->effective_itemtype, $itemtype->id, "Itemtype set correctly for item");
+
+ my $dt_from = dt_from_string();
+ my $dt_to = dt_from_string()->add( days => 7 );
+ my $dt_to_renew = dt_from_string()->add( days => 13 );
+
+ t::lib::Mocks::mock_preference('finesCalendar', 'ignoreCalendar');
+ my $issue = AddIssue( $patron->unblessed, $item->barcode, $dt_to, undef, $dt_from );
+ my $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '7.000000', "Daily rental charge calulated correctly with finesCalendar = ignoreCalendar" );
+ $accountline->delete();
+ AddRenewal( $patron->id, $item->id, $library->id, $dt_to_renew, $dt_to );
+ $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '6.000000', "Daily rental charge calulated correctly with finesCalendar = ignoreCalendar, for renewal" );
+ $accountline->delete();
+ $issue->delete();
+
+ t::lib::Mocks::mock_preference('finesCalendar', 'noFinesWhenClosed');
+ $issue = AddIssue( $patron->unblessed, $item->barcode, $dt_to, undef, $dt_from );
+ $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '7.000000', "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed" );
+ $accountline->delete();
+ AddRenewal( $patron->id, $item->id, $library->id, $dt_to_renew, $dt_to );
+ $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '6.000000', "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed, for renewal" );
+ $accountline->delete();
+ $issue->delete();
+
+ my $calendar = C4::Calendar->new( branchcode => $library->id );
+ $calendar->insert_week_day_holiday(
+ weekday => 3,
+ title => 'Test holiday',
+ description => 'Test holiday'
+ );
+ $issue = AddIssue( $patron->unblessed, $item->barcode, $dt_to, undef, $dt_from );
+ $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '6.000000', "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed and closed Wednesdays" );
+ $accountline->delete();
+ AddRenewal( $patron->id, $item->id, $library->id, $dt_to_renew, $dt_to );
+ $accountline = Koha::Account::Lines->find({ itemnumber => $item->id });
+ is( $accountline->amount, '5.000000', "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed and closed Wednesdays, for renewal" );
+ $accountline->delete();
+ $issue->delete();
+
+};
use Modern::Perl;
-use Test::More tests => 24;
use Data::Dumper;
-use Koha::Database;
+use Test::More tests => 25;
+
use t::lib::Mocks;
-use Koha::Items;
-use Koha::Biblioitems;
use t::lib::TestBuilder;
+use C4::Calendar;
+use Koha::Biblioitems;
+use Koha::Libraries;
+use Koha::Database;
+use Koha::DateUtils qw(dt_from_string);;
+use Koha::Items;
+
BEGIN {
use_ok('Koha::ItemType');
use_ok('Koha::ItemTypes');
is ( $item_type->can_be_deleted, 1, 'The item type that was being used by the removed item and biblioitem can now be deleted' );
+subtest 'Koha::ItemType::calc_rental_charge_daily tests' => sub {
+ plan tests => 4;
+
+ my $library = Koha::Libraries->search()->next();
+ my $module = new Test::MockModule('C4::Context');
+ $module->mock('userenv', sub { { branch => $library->id } });
+
+ my $itemtype = Koha::ItemType->new(
+ {
+ itemtype => 'type4',
+ description => 'description',
+ rental_charge_daily => 1.00,
+ }
+ )->store;
+
+ is( $itemtype->rental_charge_daily, 1.00, 'Daily rental charge stored and retreived correctly' );
+
+ my $dt_from = dt_from_string();
+ my $dt_to = dt_from_string()->add( days => 7 );
+
+ t::lib::Mocks::mock_preference('finesCalendar', 'ignoreCalendar');
+ my $charge = $itemtype->calc_rental_charge_daily( { from => $dt_from, to => $dt_to } );
+ is( $charge, 7.00, "Daily rental charge calulated correctly with finesCalendar = ignoreCalendar" );
+
+ t::lib::Mocks::mock_preference('finesCalendar', 'noFinesWhenClosed');
+ $charge = $itemtype->calc_rental_charge_daily( { from => $dt_from, to => $dt_to } );
+ is( $charge, 7.00, "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed" );
+
+ my $calendar = C4::Calendar->new( branchcode => $library->id );
+ $calendar->insert_week_day_holiday(
+ weekday => 3,
+ title => 'Test holiday',
+ description => 'Test holiday'
+ );
+ $charge = $itemtype->calc_rental_charge_daily( { from => $dt_from, to => $dt_to } );
+ is( $charge, 6.00, "Daily rental charge calulated correctly with finesCalendar = noFinesWhenClosed and closed Wednesdays" );
+
+};
+
$schema->txn_rollback;