# if the due_date lands on a day when the location is closed
return unless $copy and $circ->due_date;
+ $self->extend_renewal_due_date if $self->is_renewal;
+
#my $org = (ref $copy->circ_lib) ? $copy->circ_lib->id : $copy->circ_lib;
# due-date overlap should be determined by the location the item
}
}
+sub extend_renewal_due_date {
+ my $self = shift;
+ my $circ = $self->circ;
+ my $copy = $self->copy;
+
+ my $extend = $U->ou_ancestor_setting_value(
+ $self->circ_lib, 'circ.renew.extend_due_date', $self->editor);
+
+ return unless $extend;
+
+ # No value essentially means extend due dates for all renewals.
+ my $percent = $U->ou_ancestor_setting_value($self->circ_lib,
+ 'circ.renew.extend_due_date.min_duration_percent', $self->editor) || 0.001;
+
+ my $prev_circ = $self->editor->retrieve_action_circulation($self->parent_circ);
+
+ my $start_time = DateTime::Format::ISO8601->new
+ ->parse_datetime(clean_ISO8601($prev_circ->xact_start))->epoch;
+
+ my $end_time = DateTime::Format::ISO8601->new
+ ->parse_datetime(clean_ISO8601($prev_circ->due_date))->epoch;
+
+ my $now_time = DateTime->now->epoch;
+
+ my $total_duration = $end_time - $start_time;
+ my $checkout_duration = $now_time - $start_time;
+ my $checkout_percent = ($checkout_duration / $total_duration) * 100;
+
+ return if $checkout_percent < $percent;
+
+ my $remaining_duration = $end_time - $now_time;
+
+ # $circ->due_date is already in the correct timezone.
+ my $due_date = DateTime::Format::ISO8601->new
+ ->parse_datetime(clean_ISO8601($circ->due_date));
+
+ $due_date->add(seconds => $remaining_duration);
+
+ $logger->info("circulator: extended renewal due date to $due_date");
+
+ $circ->due_date($due_date->strftime('%FT%T%z'));
+}
+
sub create_due_date {
'coust', 'description'),
'integer' );
+
+INSERT into config.org_unit_setting_type (name, grp, label, description, datatype)
+VALUES (
+ 'circ.renew.extend_due_date',
+ 'circ',
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date',
+ 'Extend Renwal Due Dates For Early Renewal',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date',
+ 'Due dates for renewals will be calculated as the circ duration ' ||
+ 'plus any time lost from the previous circulation caused by ' ||
+ 'early renewal',
+ 'coust',
+ 'description'
+ ),
+ 'interval'
+), (
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'circ',
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'Extend Renwal Due Dates Minimum Duration Percent',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'A renewal will only result in an extended due date when the ' ||
+ 'renewal occurs after a certain percentage of the total circ ' ||
+ 'duration has passed',
+ 'coust',
+ 'description'
+ ),
+ 'float'
+);
--- /dev/null
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
+
+INSERT into config.org_unit_setting_type (name, grp, label, description, datatype)
+VALUES (
+ 'circ.renew.extend_due_date',
+ 'circ',
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date',
+ 'Extend Renwal Due Dates For Early Renewal',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date',
+ 'Due dates for renewals will be calculated as the circ duration ' ||
+ 'plus any time lost from the previous circulation caused by ' ||
+ 'early renewal',
+ 'coust',
+ 'description'
+ ),
+ 'interval'
+), (
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'circ',
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'Extend Renwal Due Dates Minimum Duration Percent',
+ 'coust',
+ 'label'
+ ),
+ oils_i18n_gettext(
+ 'circ.renew.extend_due_date.min_duration_percent',
+ 'A renewal will only result in an extended due date when the ' ||
+ 'renewal occurs after a certain percentage of the total circ ' ||
+ 'duration has passed',
+ 'coust',
+ 'description'
+ ),
+ 'float'
+);
+
+COMMIT;
--- /dev/null
+== Renewal Due Date Extended to Cover Lost Time ==
+
+When an item is renewed before it's due date, libraries now have the option
+to extend the renewal's due date to include any time lost from the early
+renewal.
+
+For example, a 14 day checkout renewed after 12 days will result in a due date
+on the renewal of 14 days plus 2 days to cover the lost time.
+
+=== Org Unit Settings ===
+
+==== circ.renew.extend_due_date ====
+
+Enables this new feature
+
+==== circ.renew.extend_due_date.min_duration_percent ====
+
+Specifies how early in a checkout a renewal will result in an extended
+due date. E.g. A value of 50 (percent) means no due date extension
+would occur if an attempt to renew occurred after 5 days of a 14 day
+circulation duration. In this case, the renewal would still be allowed,
+it just wouldn't get the extended due date.
+
+