Bugzilla – Attachment 34333 Details for
Bug 12768
Replacement cost and processing fee management
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 12768 - Replacement cost and processing fee management
Bug-12768---Replacement-cost-and-processing-fee-ma.patch (text/plain), 21.19 KB, created by
simith.doliveira
on 2014-12-11 18:19:26 UTC
(
hide
)
Description:
Bug 12768 - Replacement cost and processing fee management
Filename:
MIME Type:
Creator:
simith.doliveira
Created:
2014-12-11 18:19:26 UTC
Size:
21.19 KB
patch
obsolete
>From d05288761b1d63be4b32b7bf78c4462402c202d7 Mon Sep 17 00:00:00 2001 >From: simith <simith@inlibro.com> >Date: Thu, 11 Dec 2014 13:04:55 -0500 >Subject: [PATCH] Bug 12768 - Replacement cost and processing fee management > >--- > C4/Accounts.pm | 77 ++++++++++++------- > C4/Circulation.pm | 5 +- > admin/itemtypes.pl | 16 +++- > installer/data/mysql/kohastructure.sql | 2 + > installer/data/mysql/sysprefs.sql | 2 + > installer/data/mysql/updatedatabase.pl | 10 +++ > .../intranet-tmpl/prog/en/css/staff-global.css | 4 + > .../prog/en/modules/admin/itemtypes.tt | 16 +++- > .../en/modules/admin/preferences/circulation.pref | 12 +++ > t/db_dependent/Circulation/Chargelostitem.t | 89 ++++++++++++++++++++++ > 10 files changed, 198 insertions(+), 35 deletions(-) > create mode 100644 t/db_dependent/Circulation/Chargelostitem.t > >diff --git a/C4/Accounts.pm b/C4/Accounts.pm >index c98013a..6915c4c 100644 >--- a/C4/Accounts.pm >+++ b/C4/Accounts.pm >@@ -353,43 +353,65 @@ sub chargelostitem{ > # a charge has been added > # FIXME : if no replacement price, borrower just doesn't get charged? > my $dbh = C4::Context->dbh(); >- my ($borrowernumber, $itemnumber, $amount, $description) = @_; >- >+ my ($issues, $description) = @_; >+ my $borrowernumber = $issues->{'borrowernumber'}; >+ my $itemnumber = $issues->{'itemnumber'}; >+ my $replacementprice = $issues->{'replacementprice'}; >+ my $defaultreplacecost = $issues->{'defaultreplacecost'}; >+ my $processfee = $issues->{'processfee'}; >+ my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost"); >+ my $processingfeenote = C4::Context->preference("ProcessingFeeNote"); >+ >+ if ($usedefaultreplacementcost && $replacementprice == 0){ >+ $replacementprice = $defaultreplacecost; >+ } > # first make sure the borrower hasn't already been charged for this item > my $sth1=$dbh->prepare("SELECT * from accountlines > WHERE borrowernumber=? AND itemnumber=? and accounttype='L'"); > $sth1->execute($borrowernumber,$itemnumber); > my $existing_charge_hashref=$sth1->fetchrow_hashref(); >- > # OK, they haven't >+ my $accountline; > unless ($existing_charge_hashref) { >- my $manager_id = 0; >- $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >- # This item is on issue ... add replacement cost to the borrower's record and mark it returned >- # Note that we add this to the account even if there's no replacement price, allowing some other >- # process (or person) to update it, since we don't handle any defaults for replacement prices. >- my $accountno = getnextacctno($borrowernumber); >- my $sth2=$dbh->prepare("INSERT INTO accountlines >- (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id) >- VALUES (?,?,now(),?,?,'L',?,?,?)"); >- $sth2->execute($borrowernumber,$accountno,$amount, >- $description,$amount,$itemnumber,$manager_id); > >- if ( C4::Context->preference("FinesLog") ) { >- logaction("FINES", 'CREATE', $borrowernumber, Dumper({ >- action => 'create_fee', >- borrowernumber => $borrowernumber, >- accountno => $accountno, >- amount => $amount, >- amountoutstanding => $amount, >- description => $description, >- accounttype => 'L', >- itemnumber => $itemnumber, >- manager_id => $manager_id, >- })); >+ #add processing fee >+ if ($processfee > 0){ >+ $accountline = _insert_accontlines($borrowernumber, $processfee, $description, $itemnumber, $processingfeenote, 'PF'); >+ } >+ #add replace cost >+ if ($replacementprice > 0){ >+ $accountline = _insert_accontlines($borrowernumber, $replacementprice, $description, $itemnumber, undef, 'L'); > } >+ } >+ return $accountline; >+} > >+sub _insert_accontlines { >+ my ($borrowernumber, $amount, $description, $itemnumber, $note, $accounttype) = @_; >+ my $manager_id = 0; >+ $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >+ my $accountno = getnextacctno($borrowernumber); >+ my $dbh = C4::Context->dbh(); >+ my $sth2=$dbh->prepare("INSERT INTO accountlines >+ (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id, note) >+ VALUES (?,?,now(),?,?,?,?,?,?,?)"); >+ $sth2->execute($borrowernumber,$accountno,$amount, >+ $description,$accounttype, $amount,$itemnumber,$manager_id,$note); >+ >+ if ( C4::Context->preference("FinesLog") ) { >+ logaction("FINES", 'CREATE', $borrowernumber, Dumper({ >+ action => 'create_fee', >+ borrowernumber => $borrowernumber, >+ accountno => $accountno, >+ amount => $amount, >+ amountoutstanding => $amount, >+ description => $description, >+ accounttype => $accounttype, >+ itemnumber => $itemnumber, >+ manager_id => $manager_id, >+ })); > } >+ return $accountno; > } > > =head2 manualinvoice >@@ -473,9 +495,8 @@ sub manualinvoice { > } > > sub getcharges { >- my ( $borrowerno, $timestamp, $accountno ) = @_; >+ my ( $borrowerno, $accountno ) = @_; > my $dbh = C4::Context->dbh; >- my $timestamp2 = $timestamp - 1; > my $query = ""; > my $sth = $dbh->prepare( > "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?" >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index f24f2f7..1cfb4de 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -3602,10 +3602,11 @@ sub LostItem{ > my ($itemnumber, $mark_returned) = @_; > > my $dbh = C4::Context->dbh(); >- my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title >+ my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title,itemtypes.defaultreplacecost, itemtypes.processfee > FROM issues > JOIN items USING (itemnumber) > JOIN biblio USING (biblionumber) >+ JOIN itemtypes on items.itype = itemtypes.itemtype > WHERE issues.itemnumber=?"); > $sth->execute($itemnumber); > my $issues=$sth->fetchrow_hashref(); >@@ -3619,7 +3620,7 @@ sub LostItem{ > defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!"; # zero is OK, check defined > } > if (C4::Context->preference('WhenLostChargeReplacementFee')){ >- C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'}"); >+ C4::Accounts::chargelostitem($issues, "Lost Item $issues->{'title'} $issues->{'barcode'}"); > #FIXME : Should probably have a way to distinguish this from an item that really was returned. > #warn " $issues->{'borrowernumber'} / $itemnumber "; > } >diff --git a/admin/itemtypes.pl b/admin/itemtypes.pl >index bfaa44c..3d05cc0 100755 >--- a/admin/itemtypes.pl >+++ b/admin/itemtypes.pl >@@ -116,6 +116,8 @@ if ( $op eq 'add_form' ) { > itemtype => $itemtype, > description => $data->{'description'}, > rentalcharge => sprintf( "%.2f", $data->{'rentalcharge'} ), >+ defaultreplacecost => sprintf( "%.2f", $data->{'defaultreplacecost'} ), >+ processfee => sprintf( "%.2f", $data->{'processfee'} ), > notforloan => $data->{'notforloan'}, > imageurl => $data->{'imageurl'}, > template => C4::Context->preference('template'), >@@ -144,6 +146,8 @@ elsif ( $op eq 'add_validate' ) { > UPDATE itemtypes > SET description = ? > , rentalcharge = ? >+ , defaultreplacecost = ? >+ , processfee = ? > , notforloan = ? > , imageurl = ? > , summary = ? >@@ -156,6 +160,8 @@ elsif ( $op eq 'add_validate' ) { > $sth->execute( > $input->param('description'), > $input->param('rentalcharge'), >+ $input->param('defaultreplacecost'), >+ $input->param('processfee'), > ( $input->param('notforloan') ? 1 : 0 ), > ( > $input->param('image') eq 'removeImage' ? '' : ( >@@ -168,15 +174,15 @@ elsif ( $op eq 'add_validate' ) { > $input->param('checkinmsg'), > $input->param('checkinmsgtype'), > $sip_media_type, >- $input->param('itemtype') >+ $input->param('itemtype'), > ); > } > else { # add a new itemtype & not modif an old > my $query = " > INSERT INTO itemtypes >- (itemtype,description,rentalcharge, notforloan, imageurl, summary, checkinmsg, checkinmsgtype, sip_media_type) >+ (itemtype,description, rentalcharge, defaultreplacecost, processfee, notforloan, imageurl, summary, checkinmsg, checkinmsgtype, sip_media_type) > VALUES >- (?,?,?,?,?,?,?,?,?); >+ (?,?,?,?,?,?,?,?,?,?,?); > "; > my $sth = $dbh->prepare($query); > my $image = $input->param('image'); >@@ -184,6 +190,8 @@ elsif ( $op eq 'add_validate' ) { > $input->param('itemtype'), > $input->param('description'), > $input->param('rentalcharge'), >+ $input->param('defaultreplacecost'), >+ $input->param('processfee'), > $input->param('notforloan') ? 1 : 0, > $image eq 'removeImage' ? '' : > $image eq 'remoteImage' ? $input->param('remoteImage') : >@@ -250,6 +258,8 @@ else { # DEFAULT > foreach my $itemtype ( @{$results} ) { > $itemtype->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtype->{imageurl} ); > $itemtype->{rentalcharge} = sprintf( '%.2f', $itemtype->{rentalcharge} ); >+ $itemtype->{defaultreplacecost} = sprintf( '%.2f', $itemtype->{defaultreplacecost} ); >+ $itemtype->{processfee} = sprintf( '%.2f', $itemtype->{processfee} ); > push( @loop, $itemtype ); > } > >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index 4ffbbf2..092fa0b 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -1270,6 +1270,8 @@ CREATE TABLE `itemtypes` ( -- defines the item types > itemtype varchar(10) NOT NULL default '', -- unique key, a code associated with the item type > description mediumtext, -- a plain text explanation of the item type > rentalcharge double(16,4) default NULL, -- the amount charged when this item is checked out/issued >+ defaultreplacecost double(16,4) default NULL, -- default replacement cost >+ processfee double(16,4) default NULL, -- default text be recorded in the column note when the processing fee is applied > notforloan smallint(6) default NULL, -- 1 if the item is not for loan, 0 if the item is available for loan > imageurl varchar(200) default NULL, -- URL for the item type icon > summary text, -- information from the summary field, may include HTML >diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql >index c3e308f..37026c8 100644 >--- a/installer/data/mysql/sysprefs.sql >+++ b/installer/data/mysql/sysprefs.sql >@@ -340,6 +340,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('previousIssuesDefaultSortOrder','asc','asc|desc','Specify the sort order of Previous Issues on the circulation page','Choice'), > ('printcirculationslips','1','','If ON, enable printing circulation receipts','YesNo'), > ('PrintNoticesMaxLines','0','','If greater than 0, sets the maximum number of lines an overdue notice will print. If the number of items is greater than this number, the notice will end with a warning asking the borrower to check their online account for a full list of overdue items.','Integer'), >+('ProcessingFeeNote', '', NULL, 'Set the text to be recorded in the column note, table accountlines when the processing fee (defined in item type) is applied', 'textarea'), > ('QueryAutoTruncate','1',NULL,'If ON, query truncation is enabled by default','YesNo'), > ('QueryFuzzy','1',NULL,'If ON, enables fuzzy option for searches','YesNo'), > ('QueryStemming','1',NULL,'If ON, enables query stemming','YesNo'), >@@ -455,6 +456,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('UseControlNumber','0','','If ON, record control number (w subfields) and control number (001) are used for linking of bibliographic records.','YesNo'), > ('UseCourseReserves','0',NULL,'Enable the course reserves feature.','YesNo'), > ('useDaysMode','Calendar','Calendar|Days|Datedue','Choose the method for calculating due date: select Calendar to use the holidays module, and Days to ignore the holidays module','Choice'), >+('useDefaultReplacementCost', '0', NULL, 'default replacement cost defined in item type', 'YesNo'), > ('UseICU','0','1','Tell Koha if ICU indexing is in use for Zebra or not.','YesNo'), > ('UseKohaPlugins','0','','Enable or disable the ability to use Koha Plugins.','YesNo'), > ('UseQueryParser','0',NULL,'If enabled, try to use QueryParser for queries.','YesNo'), >diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl >index cf17e0b..834fd4a 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -9585,6 +9585,16 @@ if ( CheckVersion($DBversion) ) { > SetVersion ($DBversion); > } > >+$DBversion = 'XXX'; >+if ( CheckVersion($DBversion) ) { >+ $dbh->do("ALTER TABLE `itemtypes` ADD `defaultreplacecost` DOUBLE( 16, 4 ) NULL DEFAULT NULL AFTER `rentalcharge`"); >+ $dbh->do("ALTER TABLE `itemtypes` ADD `processfee` DOUBLE( 16, 4 ) NULL DEFAULT NULL AFTER `defaultreplacecost`"); >+ $dbh->do("INSERT INTO systempreferences (variable,value,explanation,type) VALUES('useDefaultReplacementCost',0,'default replacement cost defined in item type','YesNo')"); >+ $dbh->do("INSERT INTO systempreferences (variable,value,explanation,type) VALUES('ProcessingFeeNote','','Set the text to be recorded in the column note, table accountlines when the processing fee (defined in item type) is applied','textarea')"); >+ print "Upgrade to $DBversion done (Bug 12768 - Replacement cost and processing fee management)\n"; >+ SetVersion($DBversion); >+} >+ > =head1 FUNCTIONS > > =head2 TableExists($table) >diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >index 5eb6aab2..baf40e5 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >+++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >@@ -591,6 +591,10 @@ fieldset.rows fieldset { > width: 9em; > } > >+.yui-b fieldset.rows ol.oladditemtype label, .yui-b fieldset.rows ol.oladditemtype span.label { >+ width: 13em; >+} >+ > .yui-b fieldset.rows div.hint { > margin-left : 10.5em; > } >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt >index 9a691fb..0fe80e2 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt >@@ -162,7 +162,7 @@ Item types administration > </div> > </div> > [% END %] >-<ol> >+<ol class="oladditemtype"> > <li> > <label for="notforloan">Not for loan: </label> [% IF ( notforloan ) %] > <input type="checkbox" id="notforloan" name="notforloan" checked="checked" value="1" /> >@@ -175,7 +175,15 @@ Item types administration > <li> > <label for="rentalcharge">Rental charge: </label> > <input type="text" id="rentalcharge" name="rentalcharge" size="10" value="[% rentalcharge %]" /> >- </li> >+ </li> >+ <li> >+ <label for="defaultreplacecost">Default replacement cost: </label> >+ <input type="text" id="defaultreplacecost" name="defaultreplacecost" size="10" value="[% defaultreplacecost %]" /> >+ </li> >+ <li> >+ <label for="processfee">Processing fee (when lost): </label> >+ <input type="text" id="processfee" name="processfee" size="10" value="[% processfee %]" /> >+ </li> > <li> > <label for="checkinmsg">Checkin message: </label> > <textarea id="checkinmsg" name="checkinmsg" cols="55" rows="5">[% checkinmsg %]</textarea> >@@ -262,6 +270,8 @@ Item types administration > <th>Description</th> > <th>Not for loan</th> > <th>Charge</th> >+ <th>Default replacement cost</th> >+ <th>Processing fee (when lost)</th> > <th>Checkin message</th> > <th>Actions</th> > </thead> >@@ -280,6 +290,8 @@ Item types administration > [% loo.rentalcharge %] > [% END %] > </td> >+ <td>[% loo.defaultreplacecost %]</td> >+ <td>[% loo.processfee %]</td> > <td>[% loo.checkinmsg | html_line_break %]</td> > <td> > <a href="[% loo.script_name %]?op=add_form&itemtype=[% loo.itemtype |html %]">Edit</a> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >index a296bf6..65309f9 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref >@@ -632,6 +632,18 @@ Circulation: > yes: Charge > no: "Don't Charge" > - the replacement price when a patron loses an item. >+ - >+ - pref: useDefaultReplacementCost >+ choices: >+ yes: use >+ no: "Don't use" >+ - the default replacement cost defined in item type. >+ - >+ - "Set the text to be recorded in the column 'note', table 'accountlines' when the processing fee (defined in item type) is applied." >+ - pref: ProcessingFeeNote >+ type: textarea >+ class: code >+ > Self Checkout: > - > - "Include the following JavaScript on all pages in the web-based self checkout:" >diff --git a/t/db_dependent/Circulation/Chargelostitem.t b/t/db_dependent/Circulation/Chargelostitem.t >new file mode 100644 >index 0000000..e9d9694 >--- /dev/null >+++ b/t/db_dependent/Circulation/Chargelostitem.t >@@ -0,0 +1,89 @@ >+#!/usr/bin/perl >+# >+# This Koha test module is a stub! >+# Add more tests here!!! >+ >+use strict; >+use warnings; >+use Modern::Perl; >+ >+use Test::MockModule; >+use C4::Biblio; >+use C4::Items; >+use C4::Members; >+use C4::Branch; >+use C4::Category; >+use C4::Circulation; >+use MARC::Record; >+use Test::More tests => 7; >+ >+BEGIN { >+ use_ok('C4::Accounts'); >+} >+ >+my $dbh = C4::Context->dbh; >+$dbh->{AutoCommit} = 0; >+$dbh->{RaiseError} = 1; >+$dbh->do(q|DELETE FROM accountlines|); >+ >+my $branchcode; >+my $branch_created; >+my @branches = keys %{ GetBranches() }; >+if (@branches) { >+ $branchcode = $branches[0]; >+} else { >+ $branchcode = 'B'; >+ ModBranch({ add => 1, branchcode => $branchcode, branchname => 'Branch' }); >+ $branch_created = 1; >+} >+ >+my %item_branch_infos = ( >+ homebranch => $branchcode, >+ holdingbranch => $branchcode, >+); >+ >+my ($biblionumber1) = AddBiblio(MARC::Record->new, ''); >+my $itemnumber1 = AddItem({ barcode => '0101', %item_branch_infos }, $biblionumber1); >+my $itemnumber2 = AddItem({ barcode => '0102', %item_branch_infos }, $biblionumber1); >+ >+my ($biblionumber2) = AddBiblio(MARC::Record->new, ''); >+my $itemnumber3 = AddItem({ barcode => '0203', %item_branch_infos }, $biblionumber2); >+ >+my $categorycode; >+my $category_created; >+my @categories = C4::Category->all; >+if (@categories) { >+ $categorycode = $categories[0]->{categorycode} >+} else { >+ $categorycode = 'C'; >+ C4::Context->dbh->do( >+ "INSERT INTO categories(categorycode) VALUES(?)", undef, $categorycode); >+ $category_created = 1; >+} >+ >+my $borrowernumber = AddMember(categorycode => $categorycode, branchcode => $branchcode); >+my $borrower = GetMember(borrowernumber => $borrowernumber); >+ >+# Need to mock userenv for AddIssue >+my $module = new Test::MockModule('C4::Context'); >+$module->mock('userenv', sub { { branch => $branchcode } }); >+AddIssue($borrower, '0101'); >+AddIssue($borrower, '0203'); >+ >+# Begin tests... >+my $processfee = 10; >+my $issues; >+$issues = C4::Circulation::GetIssues({biblionumber => $biblionumber1}); >+my $issue=$issues->[0]; >+$issue->{'processfee'} = $processfee; >+my $accountlineId = C4::Accounts::chargelostitem($issue, 'test'); >+ >+my @accountline = C4::Accounts::getcharges($borrowernumber, $accountlineId); >+ >+is( scalar(@accountline), 1, 'accountline should have 1 row' ); >+is( int($accountline[0]->{amount}), $processfee, "The accountline amount should be precessfee value " ); >+is( $accountline[0]->{accounttype}, 'PF', "The accountline accounttype should be PF " ); >+is( $accountline[0]->{borrowernumber}, $borrowernumber, "The accountline borrowernumber should be the exemple borrownumber" ); >+my $itemnumber = C4::Items::GetItemnumberFromBarcode('0101'); >+is( $accountline[0]->{itemnumber}, $itemnumber, "The accountline itemnumber should the linked with barcode '0101'" ); >+is( $accountline[0]->{description}, 'test', "The accountline description should be 'test'" ); >-- >1.9.1
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 12768
:
34333
|
34334
|
36350
|
36505
|
36506
|
36552
|
36553
|
36554
|
36555
|
38365
|
38367
|
38368
|
38375
|
39298
|
39299
|
39300
|
39999
|
40000
|
40001
|
40002
|
42157
|
42158
|
43181
|
43546
|
64775
|
64776
|
66760
|
66761
|
67875
|
67876
|
67877
|
67878
|
67891
|
67892
|
67893
|
67894
|
67895
|
67896
|
67897
|
68035
|
68036
|
68037
|
68038
|
68039
|
68040
|
68041
|
68042
|
68076
|
68264
|
68265
|
68266
|
68267
|
68268
|
68269
|
68270
|
68271
|
68272
|
68273
|
68274
|
68332
|
68415
|
68416
|
68417
|
68426
|
68427