Bug 37762: Circulation: Hook to checkouts/checkins
Signed-off-by: Jason Robb <jrobb@sekls.org> Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com> Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
950c9ccb96
commit
db7854682e
|
|
@ -105,6 +105,7 @@ use Koha::DateUtils qw( dt_from_string );
|
|||
use Koha::Calendar;
|
||||
use Koha::Checkouts;
|
||||
use Koha::ILL::Requests;
|
||||
use Koha::ILL::ISO18626::Requests;
|
||||
use Koha::Items;
|
||||
use Koha::Patrons;
|
||||
use Koha::Patron::Debarments qw( DelUniqueDebarment AddUniqueDebarment );
|
||||
|
|
@ -1405,6 +1406,25 @@ sub CanBookBeIssued {
|
|||
}
|
||||
}
|
||||
|
||||
if ( C4::Context->preference("ILLModule") ) {
|
||||
|
||||
my $is_ill_partner = ( $patron->categorycode eq C4::Context->preference("ILLPartnerCode") );
|
||||
my $iso18626_hold = Koha::Holds->find(
|
||||
{
|
||||
itemnumber => $item_object->itemnumber,
|
||||
borrowernumber => $patron->borrowernumber
|
||||
}
|
||||
);
|
||||
|
||||
if ($iso18626_hold) {
|
||||
my $iso18626_request = $iso18626_hold->iso18626_request;
|
||||
if ( $is_ill_partner && $iso18626_hold && $iso18626_request ) {
|
||||
$needsconfirmation{SUPPLY_ILL} = 1;
|
||||
$needsconfirmation{'iso18626_payload_supplyill'} = $iso18626_request->iso18626_request_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( \%issuingimpossible, \%needsconfirmation, \%alerts, \%messages );
|
||||
}
|
||||
|
||||
|
|
@ -1646,6 +1666,7 @@ sub AddIssue {
|
|||
my $switch_onsite_checkout = $params && $params->{switch_onsite_checkout};
|
||||
my $auto_renew = $params && $params->{auto_renew};
|
||||
my $cancel_recall = $params && $params->{cancel_recall};
|
||||
my $iso18626_payload = $params && $params->{iso18626_payload};
|
||||
my $recall_id = $params && $params->{recall_id};
|
||||
my $confirmations = $params->{confirmations};
|
||||
my $forced = $params->{forced};
|
||||
|
|
@ -2017,6 +2038,19 @@ sub AddIssue {
|
|||
);
|
||||
}
|
||||
|
||||
my $iso18626_request =
|
||||
Koha::ILL::ISO18626::Requests->find( $params->{iso18626_payload}->{iso18626_payload_supplyill} );
|
||||
if ($iso18626_request) {
|
||||
$iso18626_request->issue_id( $issue->issue_id )->store();
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{
|
||||
'messageInfoNote' => $params->{iso18626_payload}->{iso18626_messageInfo_note},
|
||||
'status' => 'Loaned'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Koha::Plugins->call(
|
||||
'after_circ_action',
|
||||
{
|
||||
|
|
@ -2311,6 +2345,7 @@ sub AddReturn {
|
|||
$return_date //= dt_from_string();
|
||||
my $messages;
|
||||
my $patron;
|
||||
my $iso18626_request;
|
||||
my $doreturn = 1;
|
||||
my $validTransfer = 1;
|
||||
my $stat_type = 'return';
|
||||
|
|
@ -2332,6 +2367,7 @@ sub AddReturn {
|
|||
"Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existent borrowernumber '"
|
||||
. $issue->borrowernumber . "'\n"
|
||||
. Dumper( $issue->unblessed ) . "\n";
|
||||
$iso18626_request = $issue->iso18626_request;
|
||||
} else {
|
||||
$messages->{'NotIssued'} = $barcode;
|
||||
$item->onloan(undef)->store( { skip_record_index => 1, skip_holds_queue => 1 } ) if defined $item->onloan;
|
||||
|
|
@ -2821,6 +2857,13 @@ sub AddReturn {
|
|||
if ( $doreturn and $issue ) {
|
||||
my $checkin = Koha::Old::Checkouts->find( $issue->id );
|
||||
|
||||
if ($iso18626_request) {
|
||||
$iso18626_request->progress_request(
|
||||
'supplyingAgency',
|
||||
{ 'status' => 'LoanCompleted' }
|
||||
);
|
||||
}
|
||||
|
||||
Koha::Plugins->call(
|
||||
'after_circ_action',
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use Koha::Checkouts::Renewals;
|
|||
use Koha::Checkouts::ReturnClaims;
|
||||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use Koha::ILL::ISO18626::Request;
|
||||
use Koha::Items;
|
||||
use Koha::Libraries;
|
||||
|
||||
|
|
@ -136,6 +137,19 @@ sub patron {
|
|||
return Koha::Patron->_new_from_dbic($patron_rs);
|
||||
}
|
||||
|
||||
=head3 iso18626_request
|
||||
|
||||
Returns the related Koha::ILL::ISO18626::Request object for this checkout
|
||||
|
||||
=cut
|
||||
|
||||
sub iso18626_request {
|
||||
my ($self) = @_;
|
||||
my $rs = $self->_result->iso18626_request;
|
||||
return unless $rs;
|
||||
return Koha::ILL::ISO18626::Request->_new_from_dbic($rs);
|
||||
}
|
||||
|
||||
=head3 issuer
|
||||
|
||||
my $issuer = $checkout->issuer
|
||||
|
|
|
|||
|
|
@ -108,6 +108,14 @@ ISO18626 Requesting Agency action that requires a manual response (yes or no)
|
|||
|
||||
ID of the hold related to this ISO18626 request
|
||||
|
||||
=head2 issue_id
|
||||
|
||||
data_type: 'integer'
|
||||
is_foreign_key: 1
|
||||
is_nullable: 1
|
||||
|
||||
ID of the checkout related to this ISO18626 request
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
|
|
@ -181,6 +189,8 @@ __PACKAGE__->add_columns(
|
|||
},
|
||||
"hold_id",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
"issue_id",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
);
|
||||
|
||||
=head1 PRIMARY KEY
|
||||
|
|
@ -197,6 +207,18 @@ __PACKAGE__->set_primary_key("iso18626_request_id");
|
|||
|
||||
=head1 UNIQUE CONSTRAINTS
|
||||
|
||||
=head2 C<uniq_issue_id>
|
||||
|
||||
=over 4
|
||||
|
||||
=item * L</issue_id>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_unique_constraint("uniq_issue_id", ["issue_id"]);
|
||||
|
||||
=head2 C<uniq_reserve_id>
|
||||
|
||||
=over 4
|
||||
|
|
@ -263,9 +285,29 @@ __PACKAGE__->belongs_to(
|
|||
{ is_deferrable => 1, on_delete => "RESTRICT", on_update => "CASCADE" },
|
||||
);
|
||||
|
||||
=head2 issue
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-02-24 13:34:37
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7KqpCOYXvp6skCK/lTer0g
|
||||
Type: belongs_to
|
||||
|
||||
Related object: L<Koha::Schema::Result::Issue>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"issue",
|
||||
"Koha::Schema::Result::Issue",
|
||||
{ issue_id => "issue_id" },
|
||||
{
|
||||
is_deferrable => 1,
|
||||
join_type => "LEFT",
|
||||
on_delete => "SET NULL",
|
||||
on_update => "CASCADE",
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-02-24 13:40:32
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:IYorMR5/Rcx1W9dZv2WVSw
|
||||
|
||||
=head2 koha_object_class
|
||||
|
||||
|
|
|
|||
|
|
@ -330,6 +330,21 @@ __PACKAGE__->belongs_to(
|
|||
{ is_deferrable => 1, on_delete => "RESTRICT", on_update => "CASCADE" },
|
||||
);
|
||||
|
||||
=head2 iso18626_request
|
||||
|
||||
Type: might_have
|
||||
|
||||
Related object: L<Koha::Schema::Result::Iso18626Request>
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->might_have(
|
||||
"iso18626_request",
|
||||
"Koha::Schema::Result::Iso18626Request",
|
||||
{ "foreign.issue_id" => "self.issue_id" },
|
||||
{ cascade_copy => 0, cascade_delete => 0 },
|
||||
);
|
||||
|
||||
=head2 issuer
|
||||
|
||||
Type: belongs_to
|
||||
|
|
@ -366,8 +381,8 @@ __PACKAGE__->belongs_to(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-09-05 20:52:03
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CHRrFP4okgRBpRmN5DG5iw
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2026-02-24 13:37:30
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:A2+qWGBNGZgyi3aAVH5/wQ
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
'+auto_renew' => { is_boolean => 1 },
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ properties:
|
|||
requestingAgencyRequestId:
|
||||
type: string
|
||||
description: Requesting agency request ID or number
|
||||
issue_id:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
description: Associated checkout internal identifier
|
||||
iso18626_requesting_agency_id:
|
||||
type: integer
|
||||
description: Associated ISO18626 requesting agency internal identifier
|
||||
|
|
|
|||
|
|
@ -191,6 +191,16 @@ my $recall_id = $query->param('recall_id');
|
|||
my $debt_confirmed = $query->param('debt_confirmed') || 0; # Don't show the debt error dialog twice
|
||||
my $charges = $query->param('charges') || q{};
|
||||
|
||||
my @allowed_iso18626_fields = qw(
|
||||
iso18626_payload_supplyill
|
||||
iso18626_messageInfo_note
|
||||
);
|
||||
|
||||
my %iso18626_payload = map {
|
||||
my $val = $query->param($_);
|
||||
defined $val ? ( $_ => $val ) : ()
|
||||
} @allowed_iso18626_fields;
|
||||
|
||||
# Check if stickyduedate is turned off
|
||||
if (@$barcodes) {
|
||||
|
||||
|
|
@ -597,6 +607,7 @@ if ( @$barcodes && $op eq 'cud-checkout' ) {
|
|||
auto_renew => $session->param('auto_renew'),
|
||||
switch_onsite_checkout => $switch_onsite_checkout,
|
||||
cancel_recall => $cancel_recall,
|
||||
iso18626_payload => \%iso18626_payload,
|
||||
recall_id => $recall_id,
|
||||
confirmations => [ grep { /^[A-Z_]+$/ } keys %{$needsconfirmation} ],
|
||||
forced => [ keys %{$issuingimpossible} ]
|
||||
|
|
|
|||
|
|
@ -33,4 +33,9 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
|||
}
|
||||
);
|
||||
|
||||
my $userenv = C4::Context->userenv;
|
||||
$template->param(
|
||||
userenv => $userenv,
|
||||
);
|
||||
|
||||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
|
|
|
|||
|
|
@ -3821,10 +3821,13 @@ CREATE TABLE `iso18626_requests` (
|
|||
`service_type` enum('Copy','Loan','CopyOrLoan') NOT NULL COMMENT 'ISO18626 service type',
|
||||
`pending_requesting_agency_action` enum('Cancel','Renew') DEFAULT NULL COMMENT 'ISO18626 Requesting Agency action that requires a manual response (yes or no)',
|
||||
`hold_id` int(11) DEFAULT NULL COMMENT 'ID of the hold related to this ISO18626 request',
|
||||
>>>>>>> 16e751e7126 (Bug 37762: Circulation: Hook to holds)
|
||||
`issue_id` int(11) DEFAULT NULL COMMENT 'ID of the checkout related to this ISO18626 request',
|
||||
PRIMARY KEY (`iso18626_request_id`),
|
||||
UNIQUE KEY `uniq_reserve_id` (`hold_id`),
|
||||
UNIQUE KEY `uniq_issue_id` (`issue_id`),
|
||||
KEY `iso18626_rafk` (`iso18626_requesting_agency_id`),
|
||||
CONSTRAINT `uniq_reserve_id` FOREIGN KEY (`hold_id`) REFERENCES `reserves` (`reserve_id`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT `uniq_issue_id` FOREIGN KEY (`issue_id`) REFERENCES `issues` (`issue_id`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT `iso18626_rafk` FOREIGN KEY (`iso18626_requesting_agency_id`) REFERENCES `iso18626_requesting_agencies` (`iso18626_requesting_agency_id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
|
|
|||
|
|
@ -217,6 +217,10 @@
|
|||
</li>
|
||||
[% END %]
|
||||
|
||||
[% IF ( SUPPLY_ILL ) %]
|
||||
<li class="needsconfirm">You're checking out a supply ILL to an ILL partner. The corresponding supply ILL will be marked as 'Loaned'. Please enter the required information. </li>
|
||||
[% END %]
|
||||
|
||||
[% IF TOO_MANY and TOO_MANY == 'TOO_MANY_CHECKOUTS' %]
|
||||
<li class="needsconfirm too_many_checkouts">Too many checked out. [% current_loan_count | html %] checked out, only [% max_loans_allowed | html %] are allowed.</li>
|
||||
<li class="needsconfirm too_many_checkouts2"> Maximum checkouts calculated from the circulation rule for [% INCLUDE circulation_rule_criteria rule=circulation_rule_TOO_MANY %] </li>
|
||||
|
|
@ -405,6 +409,12 @@
|
|||
|
||||
[% IF ( DEBT ) %]<input type="hidden" name="debt_confirmed" value="1" />[% END %]
|
||||
|
||||
[% IF ( SUPPLY_ILL ) %]
|
||||
<label for="iso18626_messageInfo_note">Enter ISO18626 message here</label>
|
||||
<input type="text" name="iso18626_messageInfo_note" value="" />
|
||||
<input type="hidden" name="iso18626_payload_supplyill" value="[% iso18626_payload_supplyill | html %]" />
|
||||
[% END %]
|
||||
|
||||
[% IF ( INVALID_DATE ) %]
|
||||
<p>
|
||||
<input type="text" size="20" id="confirm_duedatespec" name="duedatespec" value="[% duedatespec | html %]" class="flatpickr" data-flatpickr-enable-time="true" data-flatpickr-on-close-focus="#barcode" />
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
[% INCLUDE 'js-date-format.inc' %]
|
||||
<script nonce="[% Koha.CSPNonce | $raw %]">
|
||||
const supplying_ill_table_settings = [% TablesSettings.GetTableSettings( 'illrequests', 'ill-requests', 'ill-requests', 'json' ) | $raw %];
|
||||
const userenv = [% To.json(userenv) | $raw %];
|
||||
</script>
|
||||
[% Asset.js("js/vue/dist/ill.js") | $raw %]
|
||||
[% END %]
|
||||
|
|
|
|||
|
|
@ -248,6 +248,13 @@ function LoadIssuesTable() {
|
|||
".</span>";
|
||||
}
|
||||
|
||||
if (oObj.iso18626_request) {
|
||||
title += create_iso18626_request_link(
|
||||
oObj.iso18626_request.id,
|
||||
oObj.iso18626_request.status
|
||||
);
|
||||
}
|
||||
|
||||
title +=
|
||||
" " +
|
||||
"<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=" +
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ export class ItemAPIClient {
|
|||
params,
|
||||
headers,
|
||||
}),
|
||||
get: id =>
|
||||
this.httpClient.get({
|
||||
endpoint: "items/" + id,
|
||||
headers: {
|
||||
"x-koha-embed": "+strings",
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,17 +86,18 @@ export default {
|
|||
},
|
||||
{
|
||||
id: "Loaned",
|
||||
confirm_message: $__(
|
||||
"The item is currently on loan to the requesting library for this request"
|
||||
),
|
||||
button_label: $__("Mark as loaned"),
|
||||
icon: "fa-box",
|
||||
dont_show: iso18626_request => true, //This is handled by Koha check out
|
||||
// confirm_message: $__(
|
||||
// "The item is currently on loan to the requesting library for this request"
|
||||
// ),
|
||||
// button_label: $__("Mark as loaned"),
|
||||
// icon: "fa-box",
|
||||
next_actions: [
|
||||
"Overdue",
|
||||
"LoanCompleted",
|
||||
"CompletedWithoutReturn",
|
||||
], //[ 'Recalled', 'HoldReturn' ]
|
||||
action_inputs: [],
|
||||
// action_inputs: [],
|
||||
},
|
||||
{
|
||||
id: "Overdue",
|
||||
|
|
@ -639,6 +640,32 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
if (resource?.hold?.item_id) {
|
||||
show_buttons.push({
|
||||
cssClass: "btn btn-primary",
|
||||
title: "Mark as loaned (Checkout)",
|
||||
icon: "fa-box",
|
||||
onClick: () => {
|
||||
if (resource.hold.item_id) {
|
||||
getItem(resource.hold.item_id).then(
|
||||
result => {
|
||||
const item_barcode = result.external_id;
|
||||
performCheckout({
|
||||
borrowernumber:
|
||||
resource.requesting_agency
|
||||
.patron_id,
|
||||
branch: userenv?.branch,
|
||||
barcode: item_barcode,
|
||||
supplyill: resource.iso18626_request_id,
|
||||
});
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (resource.status == "RequestReceived") {
|
||||
show_buttons.push({
|
||||
cssClass: "btn btn-primary",
|
||||
|
|
@ -685,6 +712,32 @@ export default {
|
|||
};
|
||||
};
|
||||
|
||||
const performCheckout = params => {
|
||||
const url = "/cgi-bin/koha/circ/circulation.pl";
|
||||
const csrfMeta = document.querySelector('meta[name="csrf-token"]');
|
||||
params.csrf_token = csrfMeta
|
||||
? csrfMeta.getAttribute("content")
|
||||
: "";
|
||||
params.op = "cud-checkout";
|
||||
|
||||
const form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = url;
|
||||
|
||||
for (const key in params) {
|
||||
if (params.hasOwnProperty(key)) {
|
||||
const hiddenField = document.createElement("input");
|
||||
hiddenField.type = "hidden";
|
||||
hiddenField.name = key;
|
||||
hiddenField.value = params[key];
|
||||
form.appendChild(hiddenField);
|
||||
}
|
||||
}
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
};
|
||||
|
||||
const baseResource = useBaseResource({
|
||||
resourceName: "iso18626_request",
|
||||
nameAttr: "iso18626_request_id",
|
||||
|
|
@ -784,6 +837,13 @@ export default {
|
|||
hideIn: ["List", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
name: "issue_id",
|
||||
label: $__("Checkout"),
|
||||
type: "boolean",
|
||||
hideIn: ["List", "Form"],
|
||||
group: $__("Request details"),
|
||||
},
|
||||
{
|
||||
group: $__("ISO18626 Messages"),
|
||||
name: "messages",
|
||||
|
|
@ -831,7 +891,18 @@ export default {
|
|||
is_hidden: 0,
|
||||
cannot_be_toggled: 0,
|
||||
cannot_be_modified: 0,
|
||||
columnname: "requestingAgencyId",
|
||||
columnname: "requesting_agency",
|
||||
render: function (data, type, row, meta) {
|
||||
return (
|
||||
'<a target="_blank" href="/cgi-bin/koha/ill/ill-requests.pl?' +
|
||||
"op=illview&illrequest_id=" +
|
||||
encodeURIComponent(data) +
|
||||
'">' +
|
||||
escape_str(row.id_prefix) +
|
||||
escape_str(data) +
|
||||
"</a>"
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
is_hidden: 0,
|
||||
|
|
@ -885,6 +956,16 @@ export default {
|
|||
},
|
||||
};
|
||||
|
||||
const getItem = async item_id => {
|
||||
const client = APIClient.item;
|
||||
return await client.items.get(item_id).then(
|
||||
result => {
|
||||
return result;
|
||||
},
|
||||
error => {}
|
||||
);
|
||||
};
|
||||
|
||||
const afterResourceFetch = (componentData, resource, caller) => {
|
||||
if (caller === "show") {
|
||||
//TODO: Use dateformat sys pref?
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use Koha::AuthorisedValues;
|
|||
use Koha::DateUtils qw( dt_from_string output_pref );
|
||||
use Koha::Items;
|
||||
use Koha::ItemTypes;
|
||||
use Koha::ILL::ISO18626::Requests;
|
||||
|
||||
my $input = CGI->new;
|
||||
|
||||
|
|
@ -242,6 +243,8 @@ while ( my $c = $sth->fetchrow_hashref() ) {
|
|||
}
|
||||
}
|
||||
|
||||
my $iso18626_request = Koha::ILL::ISO18626::Requests->get_request_by_issue_id( $c->{issue_id} );
|
||||
|
||||
my $checkout = {
|
||||
DT_RowId => $c->{itemnumber} . '-' . $c->{borrowernumber},
|
||||
title => $c->{title},
|
||||
|
|
@ -308,8 +311,14 @@ while ( my $c = $sth->fetchrow_hashref() ) {
|
|||
firstname => $c->{firstname},
|
||||
cardnumber => $c->{cardnumber},
|
||||
},
|
||||
issued_today => !$c->{not_issued_today},
|
||||
recalled => $recalled,
|
||||
issued_today => !$c->{not_issued_today},
|
||||
recalled => $recalled,
|
||||
iso18626_request => $iso18626_request
|
||||
? {
|
||||
id => $iso18626_request->iso18626_request_id,
|
||||
status => $iso18626_request->status,
|
||||
}
|
||||
: undef,
|
||||
};
|
||||
|
||||
if ( $c->{not_issued_today} ) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue